mirror of
https://github.com/zadam/trilium.git
synced 2025-12-06 07:24:25 +01:00
Merge branch 'main' into feature/manifest-v3-update
This commit is contained in:
commit
8616a65015
2
apps/website/.gitignore
vendored
2
apps/website/.gitignore
vendored
@ -24,5 +24,5 @@ dist-ssr
|
||||
*.sw?
|
||||
|
||||
*.d.ts
|
||||
!types-assets.d.ts
|
||||
!types.d.ts
|
||||
*.map
|
||||
BIN
apps/website/original-images/screenshot_desktop_linux_dark.png
Normal file
BIN
apps/website/original-images/screenshot_desktop_linux_dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
BIN
apps/website/original-images/screenshot_desktop_linux_light.png
Normal file
BIN
apps/website/original-images/screenshot_desktop_linux_light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 169 KiB |
@ -5,7 +5,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
"preview": "pnpm build && vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"preact": "^10.26.9",
|
||||
@ -17,6 +17,7 @@
|
||||
"eslint": "^9.36.0",
|
||||
"eslint-config-preact": "^2.0.0",
|
||||
"typescript": "^5.9.2",
|
||||
"user-agent-data-types": "0.4.2",
|
||||
"vite": "^7.0.4"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
||||
BIN
apps/website/public/screenshot_desktop_linux_dark.webp
Normal file
BIN
apps/website/public/screenshot_desktop_linux_dark.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
apps/website/public/screenshot_desktop_linux_light.webp
Normal file
BIN
apps/website/public/screenshot_desktop_linux_light.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
@ -11,20 +11,44 @@ interface DownloadButtonProps {
|
||||
|
||||
export default function DownloadButton({ big }: DownloadButtonProps) {
|
||||
const [ recommendedDownload, setRecommendedDownload ] = useState<RecommendedDownload | null>();
|
||||
useEffect(() => setRecommendedDownload(getRecommendedDownload()), []);
|
||||
useEffect(() => {
|
||||
getRecommendedDownload()?.then(setRecommendedDownload);
|
||||
}, []);
|
||||
|
||||
return (recommendedDownload &&
|
||||
<Button
|
||||
className={`download-button desktop-only ${big ? "big" : ""}`}
|
||||
href={recommendedDownload.url}
|
||||
iconSvg={downloadIcon}
|
||||
text={<>
|
||||
Download now{" "}
|
||||
{big
|
||||
? <span class="platform">v{packageJson.version} for {recommendedDownload.name}</span>
|
||||
: <span class="platform">for {recommendedDownload.name}</span>
|
||||
}
|
||||
</>}
|
||||
/>
|
||||
<>
|
||||
{recommendedDownload.platform !== "linux"
|
||||
? (
|
||||
<Button
|
||||
className={`download-button desktop-only ${big ? "big" : ""}`}
|
||||
href={recommendedDownload.url}
|
||||
iconSvg={downloadIcon}
|
||||
text={<>
|
||||
Download now{" "}
|
||||
{big
|
||||
? <span class="platform">v{packageJson.version} for {recommendedDownload.name}</span>
|
||||
: <span class="platform">for {recommendedDownload.name}</span>
|
||||
}
|
||||
</>}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
className={`download-button desktop-only ${big ? "big" : ""}`}
|
||||
href="/get-started/"
|
||||
iconSvg={downloadIcon}
|
||||
text={<>
|
||||
Download now{" "}
|
||||
{big
|
||||
? <span class="platform">v{packageJson.version} for Linux</span>
|
||||
: <span class="platform">for Linux</span>
|
||||
}
|
||||
</>}
|
||||
/>
|
||||
)}
|
||||
|
||||
{big && (
|
||||
<a class="more-download-options desktop-only" href="./get-started/">More platforms & server setup</a>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -75,8 +75,7 @@ header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
align-self: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.menu-toggle {
|
||||
|
||||
@ -19,6 +19,7 @@ export interface DownloadMatrixEntry {
|
||||
description: Record<Architecture, string> | string;
|
||||
downloads: Record<string, DownloadInfo>;
|
||||
helpUrl?: string;
|
||||
quickStartTitle?: string;
|
||||
quickStartCode?: string;
|
||||
}
|
||||
|
||||
@ -43,6 +44,7 @@ export const downloadMatrix: DownloadMatrix = {
|
||||
x64: "Compatible with Intel or AMD devices running Windows 10 and 11.",
|
||||
arm64: "Compatible with ARM devices (e.g. with Qualcomm Snapdragon).",
|
||||
},
|
||||
quickStartTitle: "To install via Winget:",
|
||||
quickStartCode: "winget install TriliumNext.Notes",
|
||||
downloads: {
|
||||
exe: {
|
||||
@ -55,10 +57,6 @@ export const downloadMatrix: DownloadMatrix = {
|
||||
scoop: {
|
||||
name: "Scoop",
|
||||
url: "https://scoop.sh/#/apps?q=trilium&id=7c08bc3c105b9ee5c00dd4245efdea0f091b8a5c"
|
||||
},
|
||||
winget: {
|
||||
name: "Winget",
|
||||
url: "https://github.com/microsoft/winget-pkgs/tree/master/manifests/t/TriliumNext/Notes/"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -71,14 +69,15 @@ export const downloadMatrix: DownloadMatrix = {
|
||||
x64: "For most Linux distributions, compatible with x86_64 architecture.",
|
||||
arm64: "For ARM-based Linux distributions, compatible with aarch64 architecture.",
|
||||
},
|
||||
quickStartTitle: "Select an appropriate package format, depending on your distribution:",
|
||||
downloads: {
|
||||
deb: {
|
||||
recommended: true,
|
||||
name: "Download .deb"
|
||||
name: ".deb"
|
||||
},
|
||||
rpm: {
|
||||
recommended: true,
|
||||
name: "Download .rpm"
|
||||
name: ".rpm"
|
||||
},
|
||||
flatpak: {
|
||||
name: ".flatpak"
|
||||
@ -105,6 +104,7 @@ export const downloadMatrix: DownloadMatrix = {
|
||||
x64: "For Intel-based Macs running macOS Big Sur or later.",
|
||||
arm64: "For Apple Silicon Macs such as those with M1 and M2 chips.",
|
||||
},
|
||||
quickStartTitle: "To install via Homebrew:",
|
||||
quickStartCode: "brew install --cask trilium-notes",
|
||||
downloads: {
|
||||
dmg: {
|
||||
@ -188,9 +188,14 @@ export function buildDownloadUrl(app: App, platform: Platform, format: string, a
|
||||
}
|
||||
}
|
||||
|
||||
export function getArchitecture(): Architecture | null {
|
||||
export async function getArchitecture(): Promise<Architecture | null> {
|
||||
if (typeof window === "undefined") return null;
|
||||
|
||||
if (navigator.userAgentData) {
|
||||
const { architecture } = await navigator.userAgentData.getHighEntropyValues(["architecture"]);
|
||||
return architecture?.startsWith("arm") ? "arm64" : "x64";
|
||||
}
|
||||
|
||||
const userAgent = navigator.userAgent.toLowerCase();
|
||||
if (userAgent.includes('arm64') || userAgent.includes('aarch64')) {
|
||||
return 'arm64';
|
||||
@ -212,10 +217,10 @@ export function getPlatform(): Platform | null {
|
||||
}
|
||||
}
|
||||
|
||||
export function getRecommendedDownload(): RecommendedDownload | null {
|
||||
export async function getRecommendedDownload(): Promise<RecommendedDownload | null> {
|
||||
if (typeof window === "undefined") return null;
|
||||
|
||||
const architecture = getArchitecture();
|
||||
const architecture = await getArchitecture();
|
||||
const platform = getPlatform();
|
||||
if (!platform || !architecture) return null;
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
grid-column: 1 / 4;
|
||||
}
|
||||
|
||||
.download-card {
|
||||
.download-card {
|
||||
h3 {
|
||||
color: var(--accent-color);
|
||||
font-size: 1.5em;
|
||||
@ -32,10 +32,17 @@
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
.quick-start-title {
|
||||
margin-bottom: 0;
|
||||
font-size: 0.9em;
|
||||
color: var(--muted-color);
|
||||
}
|
||||
|
||||
.quick-start {
|
||||
background-color: #ececec;
|
||||
padding: 0.75em;
|
||||
border-radius: 6px;
|
||||
margin-top: 0.5em;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background-color: black;
|
||||
@ -49,7 +56,7 @@
|
||||
}
|
||||
|
||||
.download-options {
|
||||
justify-content: flex-end;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
flex-grow: 1;
|
||||
align-items: center;
|
||||
@ -80,9 +87,19 @@
|
||||
}
|
||||
|
||||
.download-desktop {
|
||||
.download-card:first-of-type { --accent-color: var(--brand-1); }
|
||||
.download-card:nth-of-type(2) { --accent-color: var(--brand-2); }
|
||||
.download-card:last-of-type { --accent-color: var(--brand-3); }
|
||||
.download-card {
|
||||
@media (min-width: 720px) {
|
||||
transform: scale(0.9);
|
||||
|
||||
&.recommended {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
&.windows { --accent-color: var(--brand-1); }
|
||||
&.linux { --accent-color: var(--brand-2); }
|
||||
&.macos { --accent-color: var(--brand-3); }
|
||||
}
|
||||
|
||||
.download-footer {
|
||||
text-align: center;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useState } from "preact/hooks";
|
||||
import { useLayoutEffect, useState } from "preact/hooks";
|
||||
import Card from "../../components/Card.js";
|
||||
import Section from "../../components/Section.js";
|
||||
import { App, Architecture, buildDownloadUrl, downloadMatrix, DownloadMatrixEntry, getArchitecture, Platform } from "../../download-helper.js";
|
||||
import { App, Architecture, buildDownloadUrl, downloadMatrix, DownloadMatrixEntry, getArchitecture, getPlatform, Platform } from "../../download-helper.js";
|
||||
import { usePageTitle } from "../../hooks.js";
|
||||
import Button, { Link } from "../../components/Button.js";
|
||||
import Icon from "../../components/Icon.js";
|
||||
@ -10,8 +10,15 @@ import "./get-started.css";
|
||||
import packageJson from "../../../../../package.json" with { type: "json" };
|
||||
|
||||
export default function DownloadPage() {
|
||||
const [ currentArch, setCurrentArch ] = useState(getArchitecture() ?? "x64");
|
||||
usePageTitle("Download");
|
||||
const [ currentArch, setCurrentArch ] = useState<Architecture>("x64");
|
||||
const [ userPlatform, setUserPlatform ] = useState<Platform>();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
getArchitecture().then((arch) => setCurrentArch(arch ?? "x64"));
|
||||
setUserPlatform(getPlatform() ?? "windows");
|
||||
}, []);
|
||||
|
||||
usePageTitle("Get started");
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -31,7 +38,10 @@ export default function DownloadPage() {
|
||||
</div>
|
||||
|
||||
<div className="grid-3-cols download-desktop">
|
||||
{Object.entries(downloadMatrix.desktop).map(entry => <DownloadCard app="desktop" arch={currentArch} entry={entry} />)}
|
||||
{reorderPlatforms(Object.entries(downloadMatrix.desktop), userPlatform ?? "")
|
||||
.map(entry => (
|
||||
<DownloadCard app="desktop" arch={currentArch} entry={entry} isRecommended={userPlatform === entry[0]} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div class="download-footer">
|
||||
@ -41,14 +51,21 @@ export default function DownloadPage() {
|
||||
|
||||
<Section title="Set up a server for access on multiple devices">
|
||||
<div className="grid-2-cols download-server">
|
||||
{Object.entries(downloadMatrix.server).map(entry => <DownloadCard app="server" arch={currentArch} entry={entry} />)}
|
||||
{Object.entries(downloadMatrix.server).map(entry => (
|
||||
<DownloadCard app="server" arch={currentArch} entry={entry} />
|
||||
))}
|
||||
</div>
|
||||
</Section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function DownloadCard({ app, arch, entry: [ platform, entry ] }: { app: App, arch: Architecture, entry: [string, DownloadMatrixEntry] }) {
|
||||
export function DownloadCard({ app, arch, entry: [ platform, entry ], isRecommended }: {
|
||||
app: App,
|
||||
arch: Architecture,
|
||||
entry: [string, DownloadMatrixEntry],
|
||||
isRecommended?: boolean;
|
||||
}) {
|
||||
function unwrapText(text: string | Record<Architecture, string>) {
|
||||
return (typeof text === "string" ? text : text[arch]);
|
||||
}
|
||||
@ -58,20 +75,26 @@ export function DownloadCard({ app, arch, entry: [ platform, entry ] }: { app: A
|
||||
const restDownloads = allDownloads.filter(download => !download[1].recommended);
|
||||
|
||||
return (
|
||||
<Card title={<>
|
||||
{unwrapText(entry.title)}
|
||||
{entry.helpUrl && (
|
||||
<Link
|
||||
className="more-info"
|
||||
href={entry.helpUrl}
|
||||
openExternally
|
||||
>
|
||||
<Icon svg={helpIcon} />
|
||||
</Link>
|
||||
)}
|
||||
</>} className="download-card">
|
||||
<Card
|
||||
title={
|
||||
<>
|
||||
{unwrapText(entry.title)}
|
||||
{entry.helpUrl && (
|
||||
<Link
|
||||
className="more-info"
|
||||
href={entry.helpUrl}
|
||||
openExternally
|
||||
>
|
||||
<Icon svg={helpIcon} />
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
className={`download-card ${platform} ${isRecommended ? "recommended" : ""}`}
|
||||
>
|
||||
{unwrapText(entry.description)}
|
||||
|
||||
{entry.quickStartTitle && <p class="quick-start-title">{entry.quickStartTitle}</p>}
|
||||
{entry.quickStartCode && (
|
||||
<pre className="quick-start">
|
||||
<code>{entry.quickStartCode}</code>
|
||||
@ -104,3 +127,13 @@ export function DownloadCard({ app, arch, entry: [ platform, entry ] }: { app: A
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
function reorderPlatforms(entries: [string, DownloadMatrixEntry][], platformToCenter: Platform | "") {
|
||||
const entryToCenter = entries.find(x => x[0] === platformToCenter);
|
||||
if (!entryToCenter) return entries;
|
||||
|
||||
const others = entries.filter(x => x !== entryToCenter);
|
||||
const mid = Math.floor(others.length / 2);
|
||||
others.splice(mid, 0, entryToCenter);
|
||||
return others;
|
||||
}
|
||||
|
||||
@ -47,7 +47,8 @@ section.hero-section {
|
||||
}
|
||||
|
||||
.title-section {
|
||||
flex-basis: 40%;
|
||||
flex-basis: 30%;
|
||||
flex-shrink: 0;
|
||||
color: var(--muted-color);
|
||||
|
||||
h1 {
|
||||
@ -57,6 +58,10 @@ section.hero-section {
|
||||
}
|
||||
}
|
||||
|
||||
.screenshot-container {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.screenshot {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
@ -60,6 +60,7 @@ function HeroSection() {
|
||||
setScreenshotUrl(`/screenshot_desktop_mac_${colorScheme}.webp`);
|
||||
break;
|
||||
case "linux":
|
||||
setScreenshotUrl(`/screenshot_desktop_linux_${colorScheme}.webp`);
|
||||
break;
|
||||
case "windows":
|
||||
default:
|
||||
@ -76,7 +77,6 @@ function HeroSection() {
|
||||
|
||||
<div className="download-wrapper">
|
||||
<DownloadButton big />
|
||||
<a class="more-download-options desktop-only" href="./get-started/">More platforms & server setup</a>
|
||||
<Button href="./get-started/" className="mobile-only" text="Get started" />
|
||||
<div className="additional-options">
|
||||
<Button iconSvg={gitHubIcon} outline text="GitHub" href="https://github.com/TriliumNext/Trilium/" openExternally />
|
||||
@ -86,7 +86,9 @@ function HeroSection() {
|
||||
|
||||
</div>
|
||||
|
||||
{screenshotUrl && <img class="screenshot" src={screenshotUrl} alt="Screenshot of the Trilium Notes desktop application" />}
|
||||
<div className="screenshot-container">
|
||||
{screenshotUrl && <img class="screenshot" src={screenshotUrl} alt="Screenshot of the Trilium Notes desktop application" />}
|
||||
</div>
|
||||
</Section>
|
||||
)
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
:root {
|
||||
--foreground-color: #fff;
|
||||
--background-color: #0a0e14;
|
||||
--muted-color: #cacaca;
|
||||
--muted-color: #c5c5c5;
|
||||
--header-background-color: rgba(0, 0, 0, 0.75);
|
||||
--card-background-color: #ffffff12;
|
||||
--card-box-shadow: 0 0 12px rgba(0, 0, 0, 0.15);
|
||||
|
||||
1
apps/website/src/types.d.ts
vendored
Normal file
1
apps/website/src/types.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="user-agent-data-types" />
|
||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@ -787,6 +787,9 @@ importers:
|
||||
typescript:
|
||||
specifier: ^5.9.2
|
||||
version: 5.9.2
|
||||
user-agent-data-types:
|
||||
specifier: 0.4.2
|
||||
version: 0.4.2
|
||||
vite:
|
||||
specifier: ^7.0.4
|
||||
version: 7.1.7(@types/node@24.6.0)(jiti@2.6.0)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
|
||||
@ -13299,6 +13302,9 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
user-agent-data-types@0.4.2:
|
||||
resolution: {integrity: sha512-jXep3kO/dGNmDOkbDa8ccp4QArgxR4I76m3QVcJ1aOF0B9toc+YtSXtX5gLdDTZXyWlpQYQrABr6L1L2GZOghw==}
|
||||
|
||||
userhome@1.0.1:
|
||||
resolution: {integrity: sha512-5cnLm4gseXjAclKowC4IjByaGsjtAoV6PrOQOljplNB54ReUYJP8HdAFq2muHinSDAh09PPX/uXDPfdxRHvuSA==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
@ -14680,6 +14686,8 @@ snapshots:
|
||||
'@ckeditor/ckeditor5-typing': 46.1.1
|
||||
'@ckeditor/ckeditor5-utils': 46.1.1
|
||||
ckeditor5: 46.1.1(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@ckeditor/ckeditor5-autosave@46.1.1':
|
||||
dependencies:
|
||||
@ -14710,6 +14718,8 @@ snapshots:
|
||||
'@ckeditor/ckeditor5-ui': 46.1.1
|
||||
'@ckeditor/ckeditor5-utils': 46.1.1
|
||||
ckeditor5: 46.1.1(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@ckeditor/ckeditor5-bookmark@46.1.1':
|
||||
dependencies:
|
||||
@ -15026,8 +15036,6 @@ snapshots:
|
||||
'@ckeditor/ckeditor5-utils': 46.1.1
|
||||
ckeditor5: 46.1.1(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
||||
es-toolkit: 1.39.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@ckeditor/ckeditor5-editor-multi-root@46.1.1':
|
||||
dependencies:
|
||||
@ -15221,6 +15229,8 @@ snapshots:
|
||||
'@ckeditor/ckeditor5-widget': 46.1.1
|
||||
ckeditor5: 46.1.1(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
||||
es-toolkit: 1.39.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@ckeditor/ckeditor5-icons@46.1.1': {}
|
||||
|
||||
@ -29683,6 +29693,8 @@ snapshots:
|
||||
dependencies:
|
||||
react: 16.14.0
|
||||
|
||||
user-agent-data-types@0.4.2: {}
|
||||
|
||||
userhome@1.0.1: {}
|
||||
|
||||
username@5.1.0:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user