chore(website): remove old website

This commit is contained in:
Elian Doran
2025-09-27 01:42:15 +03:00
parent 3cf0ec5740
commit a11797fe6e
77 changed files with 76 additions and 904 deletions

View File

@@ -1,10 +0,0 @@
@import 'tailwindcss';
@plugin '@tailwindcss/typography';
main a {
text-decoration: revert;
}
a.rounded-full, a.rounded-xl {
text-decoration: none;
}

View File

@@ -1,13 +0,0 @@
// See https://svelte.dev/docs/kit/types#app.d.ts
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
}
export {};

View File

@@ -1,12 +0,0 @@
<!doctype html>
<html lang="%paraglide.lang%">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover" class="dark:bg-black dark:text-white">
%sveltekit.body%
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 256 256" version="1.1" viewBox="0 0 256 256" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<title>Trilium Notes</title>
<style type="text/css">
.st0{fill:#95C980;}
.st1{fill:#72B755;}
.st2{fill:#4FA52B;}
.st3{fill:#EE8C89;}
.st4{fill:#E96562;}
.st5{fill:#E33F3B;}
.st6{fill:#EFB075;}
.st7{fill:#E99547;}
.st8{fill:#E47B19;}
</style>
<g>
<path class="st0" d="m202.9 112.7c-22.5 16.1-54.5 12.8-74.9 6.3l14.8-11.8 14.1-11.3 49.1-39.3-51.2 35.9-14.3 10-14.9 10.5c0.7-21.2 7-49.9 28.6-65.4 1.8-1.3 3.9-2.6 6.1-3.8 2.7-1.5 5.7-2.9 8.8-4.1 27.1-11.1 68.5-15.3 85.2-9.5 0.1 16.2-15.9 45.4-33.9 65.9-2.4 2.8-4.9 5.4-7.4 7.8-3.4 3.5-6.8 6.4-10.1 8.8z"/>
<path class="st1" d="m213.1 104c-22.2 12.6-51.4 9.3-70.3 3.2l14.1-11.3 49.1-39.3-51.2 35.9-14.3 10c0.5-18.1 4.9-42.1 19.7-58.6 2.7-1.5 5.7-2.9 8.8-4.1 27.1-11.1 68.5-15.3 85.2-9.5 0.1 16.2-15.9 45.4-33.9 65.9-2.3 2.8-4.8 5.4-7.2 7.8z"/>
<path class="st2" d="m220.5 96.2c-21.1 8.6-46.6 5.3-63.7-0.2l49.2-39.4-51.2 35.9c0.3-15.8 3.5-36.6 14.3-52.8 27.1-11.1 68.5-15.3 85.2-9.5 0.1 16.2-15.9 45.4-33.8 66z"/>
<path class="st3" d="m106.7 179c-5.8-21 5.2-43.8 15.5-57.2l4.8 14.2 4.5 13.4 15.9 47-12.8-47.6-3.6-13.2-3.7-13.9c15.5 6.2 35.1 18.6 40.7 38.8 0.5 1.7 0.9 3.6 1.2 5.5 0.4 2.4 0.6 5 0.7 7.7 0.9 23.1-7.1 54.9-15.9 65.7-12-4.3-29.3-24-39.7-42.8-1.4-2.6-2.7-5.1-3.8-7.6-1.6-3.5-2.9-6.8-3.8-10z"/>
<path class="st4" d="m110.4 188.9c-3.4-19.8 6.9-40.5 16.6-52.9l4.5 13.4 15.9 47-12.8-47.6-3.6-13.2c13.3 5.2 29.9 15 38.1 30.4 0.4 2.4 0.6 5 0.7 7.7 0.9 23.1-7.1 54.9-15.9 65.7-12-4.3-29.3-24-39.7-42.8-1.4-2.6-2.7-5.2-3.8-7.7z"/>
<path class="st5" d="m114.2 196.5c-0.7-18 8.6-35.9 17.3-47.1l15.9 47-12.8-47.6c11.6 4.4 26.1 12.4 35.2 24.8 0.9 23.1-7.1 54.9-15.9 65.7-12-4.3-29.3-24-39.7-42.8z"/>
<path class="st6" d="m86.3 59.1c21.7 10.9 32.4 36.6 35.8 54.9l-15.2-6.6-14.5-6.3-50.6-22 48.8 24.9 13.6 6.9 14.3 7.3c-16.6 7.9-41.3 14.5-62.1 4.1-1.8-0.9-3.6-1.9-5.4-3.2-2.3-1.5-4.5-3.2-6.8-5.1-19.9-16.4-40.3-46.4-42.7-61.5 12.4-6.5 41.5-5.8 64.8-0.3 3.2 0.8 6.2 1.6 9.1 2.5 4 1.3 7.6 2.8 10.9 4.4z"/>
<path class="st7" d="m75.4 54.8c18.9 12 28.4 35.6 31.6 52.6l-14.5-6.3-50.6-22 48.7 24.9 13.6 6.9c-14.1 6.8-34.5 13-53.3 8.2-2.3-1.5-4.5-3.2-6.8-5.1-19.8-16.4-40.2-46.4-42.6-61.5 12.4-6.5 41.5-5.8 64.8-0.3 3.1 0.8 6.2 1.6 9.1 2.6z"/>
<path class="st8" d="m66.3 52.2c15.3 12.8 23.3 33.6 26.1 48.9l-50.6-22 48.8 24.9c-12.2 6-29.6 11.8-46.5 10-19.8-16.4-40.2-46.4-42.6-61.5 12.4-6.5 41.5-5.8 64.8-0.3z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="27.68" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 296">
<path fill="#673AB8" d="m128 0l128 73.9v147.8l-128 73.9L0 221.7V73.9z"></path>
<path fill="#FFF" d="M34.865 220.478c17.016 21.78 71.095 5.185 122.15-34.704c51.055-39.888 80.24-88.345 63.224-110.126c-17.017-21.78-71.095-5.184-122.15 34.704c-51.055 39.89-80.24 88.346-63.224 110.126Zm7.27-5.68c-5.644-7.222-3.178-21.402 7.573-39.253c11.322-18.797 30.541-39.548 54.06-57.923c23.52-18.375 48.303-32.004 69.281-38.442c19.922-6.113 34.277-5.075 39.92 2.148c5.644 7.223 3.178 21.403-7.573 39.254c-11.322 18.797-30.541 39.547-54.06 57.923c-23.52 18.375-48.304 32.004-69.281 38.441c-19.922 6.114-34.277 5.076-39.92-2.147Z"></path>
<path fill="#FFF" d="M220.239 220.478c17.017-21.78-12.169-70.237-63.224-110.126C105.96 70.464 51.88 53.868 34.865 75.648c-17.017 21.78 12.169 70.238 63.224 110.126c51.055 39.889 105.133 56.485 122.15 34.704Zm-7.27-5.68c-5.643 7.224-19.998 8.262-39.92 2.148c-20.978-6.437-45.761-20.066-69.28-38.441c-23.52-18.376-42.74-39.126-54.06-57.923c-10.752-17.851-13.218-32.03-7.575-39.254c5.644-7.223 19.999-8.261 39.92-2.148c20.978 6.438 45.762 20.067 69.281 38.442c23.52 18.375 42.739 39.126 54.06 57.923c10.752 17.85 13.218 32.03 7.574 39.254Z"></path>
<path fill="#FFF" d="M127.552 167.667c10.827 0 19.603-8.777 19.603-19.604c0-10.826-8.776-19.603-19.603-19.603c-10.827 0-19.604 8.777-19.604 19.603c0 10.827 8.777 19.604 19.604 19.604Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

View File

@@ -0,0 +1,21 @@
import { ComponentChildren } from "preact";
interface CardProps {
title: string;
imageUrl?: string;
className?: string;
children: ComponentChildren;
}
export default function Card({ title, children, imageUrl, className }: CardProps) {
return (
<div className={`card ${className}`}>
{imageUrl && <img class="image" src={imageUrl} />}
<div className="card-content">
<h3>{title}</h3>
{children}
</div>
</div>
)
}

View File

@@ -0,0 +1,19 @@
.download-button {
text-decoration: none;
background: var(--brand-1);
padding: 0.5em 1em;
border-radius: 6px;
color: white;
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3);
display: inline-block;
}
.download-button .platform {
font-size: 0.75em;
opacity: 0.75;
}
.download-button.big {
padding: 1em 2em;
margin: 1em 0;
}

View File

@@ -0,0 +1,17 @@
import { getRecommendedDownload } from "../download-helper";
import "./DownloadButton.css";
interface DownloadButtonProps {
big?: boolean;
}
const { architecture, platform, url } = getRecommendedDownload();
export default function DownloadButton({ big }: DownloadButtonProps) {
return (
<a className={`download-button ${big ? "big" : ""}`} href={url}>
Download now{" "}
<span class="platform">{platform} {architecture}</span>
</a>
)
}

View File

@@ -0,0 +1,8 @@
footer {
margin: 0;
padding: 1em 0;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
text-align: center;
color: var(--muted-color);
font-size: 0.8em;
}

View File

@@ -0,0 +1,14 @@
import "./Footer.css";
export default function Footer() {
return (
<footer>
<div class="content-wrapper">
<p>
© 2024-2025 <a href="https://github.com/eliandoran">Elian Doran</a> and the <a href="https://github.com/TriliumNext/Notes/graphs/contributors">team</a>.<br />
© 2017-2024 <a href="https://github.com/zadam">zadam</a>.
</p>
</div>
</footer>
)
}

View File

@@ -0,0 +1,55 @@
header {
padding: 1em;
position: sticky;
top: 0;
background: var(--header-background-color);
box-shadow: 0 0 6px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(20px);
z-index: 1000;
--gap: 1.25em;
}
header .content-wrapper {
display: flex;
align-items: center;
justify-items: center;
gap: var(--gap);
}
header a.banner {
display: flex;
align-items: center;
justify-items: center;
text-decoration: none;
color: inherit;
}
header > .content-wrapper,
section.hero-section > .content-wrapper {
min-width: 80vw;
}
header img {
width: 48px;
height: 48px;
}
header img+span {
font-size: 1.1em;
}
header nav {
flex-grow: 1;
display: flex;
justify-content: flex-end;
gap: var(--gap);
}
header nav a {
text-decoration: none;
color: inherit;
}
header nav a.active {
font-weight: bold;
}

View File

@@ -0,0 +1,40 @@
import "./Header.css";
import { useLocation } from 'preact-iso';
import DownloadButton from './DownloadButton';
interface HeaderLink {
url: string;
text: string;
external?: boolean;
}
const HEADER_LINKS: HeaderLink[] = [
{ url: "https://docs.triliumnotes.org/", text: "Documentation", external: true },
{ url: "/donate", text: "Support us" }
]
export function Header() {
const { url } = useLocation();
return (
<header>
<div class="content-wrapper">
<a class="banner" href="/">
<img src="./src/assets/icon-color.svg" width="300" height="300" />&nbsp;<span>Trilium Notes</span>
</a>
<nav>
{HEADER_LINKS.map(link => (
<a
href={link.url}
className={url === link.url && 'active'}
target={link.external && "_blank"}
>{link.text}</a>
))}
</nav>
<DownloadButton />
</div>
</header>
);
}

View File

@@ -0,0 +1,18 @@
import { ComponentChildren } from "preact";
interface SectionProps {
title?: string;
children: ComponentChildren;
className?: string;
}
export default function Section({ className, title, children }: SectionProps) {
return (
<section className={className}>
<div className="content-wrapper">
{title && <h2>{title}</h2>}
{children}
</div>
</section>
)
}

View File

@@ -1,4 +1,4 @@
import rootPackageJson from '../../../../package.json';
import rootPackageJson from '../../../package.json';
export type App = "desktop" | "server";

View File

@@ -1,12 +0,0 @@
import type { Handle } from '@sveltejs/kit';
import { paraglideMiddleware } from '$lib/paraglide/server';
const handleParaglide: Handle = ({ event, resolve }) => paraglideMiddleware(event.request, ({ request, locale }) => {
event.request = request;
return resolve(event, {
transformPageChunk: ({ html }) => html.replace('%paraglide.lang%', locale)
});
});
export const handle: Handle = handleParaglide;

View File

@@ -1,6 +0,0 @@
import { deLocalizeUrl } from '$lib/paraglide/runtime';
export const reroute = (request: {
url: URL;
fetch: typeof fetch;
}) => deLocalizeUrl(request.url).pathname;

View File

@@ -0,0 +1,34 @@
import { LocationProvider, Router, Route, hydrate, prerender as ssr } from 'preact-iso';
import { Header } from './components/Header.jsx';
import { Home } from './pages/Home/index.jsx';
import { NotFound } from './pages/_404.jsx';
import './style.css';
import Footer from './components/Footer.js';
import Download from './pages/Download/download.js';
import Donate from './pages/Donate/Donate.js';
export function App() {
return (
<LocationProvider>
<Header />
<main>
<Router>
<Route path="/" component={Home} />
<Route default component={NotFound} />
<Route path="/download" component={Download} />
<Route path="/donate" component={Donate} />
</Router>
</main>
<Footer />
</LocationProvider>
);
}
if (typeof window !== 'undefined') {
hydrate(<App />, document.getElementById('app'));
}
export async function prerender(data) {
return await ssr(<App {...data} />);
}

View File

@@ -1 +0,0 @@
// place files you want to import through the `$lib` alias in this folder.

View File

@@ -0,0 +1,20 @@
section.donate {
background: var(--background-color);
}
section.donate ul {
list-style-type: none;
display: flex;
gap: 0 1em;
padding: 0;
}
section.donate ul a {
display: block;
background: var(--brand-1);
padding: 0.5em 1em;
border-radius: 6px;
color: var(--foreground-color);
text-decoration: none;
text-align: center;
}

View File

@@ -0,0 +1,26 @@
import Section from "../../components/Section";
import "./Donate.css";
export default function Donate() {
return (
<>
<Section title="Financial donations" className="donate">
<p>A <a href="https://github.com/TriliumNext/Trilium/graphs/commit-activity">significant amount of time</a> is spent maintaining and bringing the best out of Trilium.</p>
<p>Consider supporting the main developer of the application via:</p>
<ul>
<li><a href="https://github.com/sponsors/eliandoran" target="_blank">GitHub Sponsors</a></li>
<li><a href="https://paypal.me/eliandoran" target="_blank">PayPal</a></li>
<li><a href="https://buymeacoffee.com/eliandoran" target="_blank">Buy Me A Coffee</a></li>
</ul>
</Section>
<Section title="Other ways to contribute">
<ul>
<li>Help us translate the application into your native language via <a href="https://hosted.weblate.org/engage/trilium/" target="_blank">Weblate</a>.</li>
</ul>
</Section>
</>
)
}

View File

@@ -0,0 +1,68 @@
.download-card {
padding: 1em;
}
.download-card h3 {
color: var(--accent-color);
font-size: 1.5em;
}
.download-options {
margin-top: 2em;
}
.download-options a.recommended {
display: block;
background: var(--accent-color);
padding: 0.5em 1em;
border-radius: calc(infinity * 1px);
color: var(--foreground-color);
margin: 1em 0;
text-decoration: none;
text-align: center;
}
.download-options .other-options {
display: flex;
gap: 0.5em 1em;
justify-content: center;
flex-wrap: wrap;
}
.download-desktop .download-card:first-of-type { --accent-color: var(--brand-1); }
.download-desktop .download-card:nth-of-type(2) { --accent-color: var(--brand-2); }
.download-desktop .download-card:last-of-type { --accent-color: var(--brand-3); }
.download-server .download-card:first-of-type { --accent-color: var(--brand-1); }
.download-server {
width: 75%;
margin: auto;
}
.architecture-switch {
display: flex;
gap: 1em;
justify-content: center;
align-items: center;
margin: 1em 0;
}
.architecture-switch a {
display: inline-block;
background: var(--card-background-color);
padding: 0.25em 0.5em;
text-decoration: none;
text-align: center;
min-width: 3em;
color: inherit;
}
.architecture-switch .toggle-wrapper {
border-radius: calc(infinity * 1px);
overflow: hidden;
}
.architecture-switch a.active {
background-color: var(--brand-1);
color: inherit;
}

View File

@@ -0,0 +1,65 @@
import { useState } from "preact/hooks";
import Card from "../../components/Card";
import Section from "../../components/Section";
import { App, Architecture, buildDownloadUrl, downloadMatrix, DownloadMatrixEntry, getArchitecture, Platform } from "../../download-helper";
import "./download.css";
export default function DownloadPage() {
const [ currentArch, setCurrentArch ] = useState(getArchitecture());
return (
<>
<Section title="Download the desktop application">
<div className="architecture-switch">
<span>Architecture:</span>
<div class="toggle-wrapper">
{(["x64", "arm64"] as const).map(arch => (
<a
href="#"
className={`arch ${arch === currentArch ? "active" : ""}`}
onClick={() => setCurrentArch(arch)}
>{arch}</a>
))}
</div>
</div>
<div className="grid-3-cols download-desktop">
{Object.entries(downloadMatrix.desktop).map(entry => <DownloadCard app="desktop" arch={currentArch} entry={entry} />)}
</div>
</Section>
<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} />)}
</div>
</Section>
</>
)
}
export function DownloadCard({ app, arch, entry: [ platform, entry ] }: { app: App, arch: Architecture, entry: [string, DownloadMatrixEntry] }) {
function unwrapText(text: string | Record<Architecture, string>) {
return (typeof text === "string" ? text : text[arch]);
}
const allDownloads = Object.entries(entry.downloads);
const recommendedDownload = allDownloads.find(download => download[1].recommended);
const restDownloads = allDownloads.filter(download => !download[1].recommended);
return (
<Card title={unwrapText(entry.title)} className="download-card">
{unwrapText(entry.description)}
<div class="download-options">
<a className="recommended" href={buildDownloadUrl(app, platform as Platform, recommendedDownload[0], arch)}>{recommendedDownload[1].name}</a>
<div class="other-options">
{restDownloads.map(download => (
<a href={buildDownloadUrl(app, platform as Platform, download[0], arch)}>{download[1].name}</a>
))}
</div>
</div>
</Card>
)
}

View File

@@ -0,0 +1,104 @@
section.hero-section {
position: relative;
background: linear-gradient(135deg, var(--light-bg-start), var(--light-bg-end));
}
section.hero-section.dark {
color: var(--text-on-dark);
background: radial-gradient(circle at top left, #0e141b, var(--bg-dark) 70%), linear-gradient(135deg, #0a0e14, #141c24);
}
/* Extra colored spots */
section.hero-section::before {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
background:
radial-gradient(40vmax 40vmax at 15% 25%, rgba(228, 123, 25, 0.25), transparent 70%),
radial-gradient(35vmax 35vmax at 75% 20%, rgba(79, 165, 43, 0.22), transparent 70%),
radial-gradient(28vmax 28vmax at 60% 75%, rgba(227, 63, 59, 0.22), transparent 70%),
radial-gradient(20vmax 20vmax at 85% 65%, rgba(228, 123, 25, 0.18), transparent 70%),
radial-gradient(15vmax 15vmax at 40% 50%, rgba(79, 165, 43, 0.15), transparent 70%);
}
@media (prefers-color-scheme: light) {
/* Soft vignette for focus */
section.hero-section::after {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(circle, rgba(255, 255, 255, 0) 60%, rgba(0, 0, 0, 0.06) 100%);
pointer-events: none;
}
}
@media (prefers-color-scheme: dark) {
section.hero-section::before {
background:
radial-gradient(40vmax 40vmax at 20% 30%, rgba(228, 123, 25, 0.25), transparent 70%),
radial-gradient(30vmax 30vmax at 75% 25%, rgba(79, 165, 43, 0.25), transparent 70%),
radial-gradient(25vmax 25vmax at 60% 75%, rgba(227, 63, 59, 0.25), transparent 70%),
radial-gradient(20vmax 20vmax at 85% 65%, rgba(228, 123, 25, 0.15), transparent 70%);
}
/* Subtle noise for depth */
section.hero-section::after {
content: "";
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200' viewBox='0 0 200 200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
opacity: 0.04;
pointer-events: none;
}
}
section.hero-section > .content-wrapper {
display: flex;
padding: 3em;
align-items: center;
justify-content: center;
min-height: 60vh;
}
section.hero-section .title-section {
flex-basis: 40%;
color: var(--muted-color);
}
section.hero-section .title-section h1 {
line-height: 1.1;
font-weight: 100;
color: var(--foreground-color);
}
section.hero-section .image,
section.hero-section .image img {
width: 100%;
height: auto;
position: relative;
}
section.hero-section .download-wrapper {
display: inline-flex;
flex-direction: column;
}
section.hero-section .download-button {
margin-bottom: 0.25em;
}
section.hero-section .more-download-options {
display: inline-block;
color: var(--brand-1);
font-size: 0.8em;
text-align: center;
}
section:nth-of-type(2n+1) {
background: linear-gradient(135deg, rgba(228, 123, 25, 0.08), rgba(79, 165, 43, 0.08));
}
.benefits-container .card {
padding: 1em;
}

View File

@@ -0,0 +1,112 @@
import { ComponentChildren } from 'preact';
import Card from '../../components/Card';
import Section from '../../components/Section';
import DownloadButton from '../../components/DownloadButton';
import "./index.css";
export function Home() {
return (
<>
<HeroSection />
<BenefitsSection />
<NoteTypesSection />
<CollectionsSection />
<FaqSection />
</>
);
}
function HeroSection() {
return (
<Section className="hero-section">
<div class="title-section">
<h1>Organize your thoughts. Build your personal knowledge base.</h1>
<p>Trilium is an open-source solution for note-taking and organizing a personal knowledge base. Use it locally on your desktop, or sync it with your self-hosted server to keep your notes everywhere you go.</p>
<div className="download-wrapper">
<DownloadButton big />
<a class="more-download-options" href="./download">more options</a>
</div>
</div>
<figure class="image"><img src="./src/assets/screenshot_desktop_win.png" /></figure>
</Section>
)
}
function BenefitsSection() {
return (
<Section className="benefits" title="Benefits">
<div className="benefits-container grid-3-cols">
<Card title="Note structure">Notes can be arranged hierarchically. There's no need for folders, since each note can contain sub-notes. A single note can be added in multiple places in the hierarchy.</Card>
<Card title="Labels and relationships between notes">Define <em> relations </em> between notes
or add <em> labels </em> for easy categorization. Using promoted attributes, there's an easy way to
enter structured information about the notes which can later be displayed in other formats such as a
table.</Card>
<Card title="Note revisions">Notes are periodically saved in the background and revisions can be used to check the old content of a note or delete accidental changes. Revisions can also be created on-demand.</Card>
<Card title="Quick search and commands">Jump quickly to notes across the hierarchy by searching for their title, with
fuzzy matching to account for typos or slight differences. Or search through all the various
commands of the application.</Card>
<Card title="Powerful search">Or search for text inside notes and narrow down the search by filtering by the parent note, or by depth.</Card>
<Card title="Protected notes">Protect sensitive personal information by encrypting the notes and locking them behind a password-protected session.</Card>
<Card title="Import/export">Easily import Markdown and ENEX formats from other note-taking applications, or export to Markdown or HTML.</Card>
<Card title="Workspaces and hoisting">Easily separate your personal and work notes by grouping them under a workspace, which focuses your note tree to only show a specific set of notes.</Card>
<Card title="Web clipper">Grab web pages (or screenshots) and place them directly into Trilium using the web clipper browser extension.</Card>
<Card title="Synchronization">Use a self-hosted or cloud instance to easily synchronize your notes across multiple devices, and to access it from your mobile phone using a PWA (progressive web application).</Card>
<Card title="Share notes on the web">If you have a server instance, you can easily use it to share a subset of your notes with other people.</Card>
<Card title="Advanced scripting and REST API">Create your own integrations within Trilium by writing custom widgets, or custom-server side logic. Interact externally with the Trilium database by using the built-in REST API.</Card>
</div>
</Section>
);
}
function NoteTypesSection() {
return (
<Section className="note-types" title="Note types">
<div class="note-types-container grid-3-cols">
<Card title="Text notes" imageUrl="./src/assets/type_text.png">The notes are edited using a visual (WYSIWYG) editor, with support for tables, images, math expressions, code blocks with syntax highlighting. Quickly format the text using Markdown-like syntax or using slash commands.</Card>
<Card title="Code notes" imageUrl="./src/assets/type_code.png">Large samples of source code or scripts use a dedicated editor, with syntax highlighting for many programming languages and with various color themes.</Card>
<Card title="File notes" imageUrl="./src/assets/type_file.png">Embed multimedia files such as PDFs, images, videos with an in-application preview.</Card>
<Card title="Canvas" imageUrl="./src/assets/type_canvas.png">Arrange shapes, images and text across an infinite canvas, using the same technology behind <a href="https://excalidraw.com">excalidraw.com</a>. Ideal for diagrams, sketches and visual planning.</Card>
<Card title="Mermaid diagrams" imageUrl="./src/assets/type_mermaid.png">Create diagrams such as flowcharts, class &amp; sequence diagrams, Gantt charts and many more, using the Mermaid syntax.</Card>
<Card title="Mindmap" imageUrl="./src/assets/type_mindmap.png">Organize your thoughts visually or do a brainstorming session by using <a href="https://en.wikipedia.org/wiki/Mind_map">mind map diagrams</a>.</Card>
</div>
<p>and others: note map, relation map, saved searches, render note, web views.</p>
</Section>
);
}
function CollectionsSection() {
return (
<Section className="collections" title="Collections">
<div className="collections-container grid-2-cols">
<Card title="Calendar" imageUrl="./src/assets/collection_calendar.png">Organize your personal or professional events using a calendar, with support for all-day and multi-day events. See your events at a glance with the week, month and year views. Easy interaction to add or drag events.</Card>
<Card title="Table" imageUrl="./src/assets/collection_table.png">Display and edit information about notes in a tabular structure, with various column types such as text, number, check boxes, date &amp; time, links and colors and support for relations. Optionally, display the notes within a tree hierarchy inside the table.</Card>
<Card title="Board" imageUrl="./src/assets/collection_board.png">Organize your tasks or project status into a Kanban board with an easy way to create new items and columns and simply changing their status by dragging across the board.</Card>
<Card title="Geomap" imageUrl="./src/assets/collection_geomap.png">Plan your vacations or mark your points of interest directly on a geographical map using customizable markers. Display recorded GPX tracks to track itineraries.</Card>
</div>
</Section>
);
}
function FaqSection() {
return (
<Section className="faq" title="Frequently Asked Questions">
<FaqItem question="Where is the data stored?">All your notes will be stored in an SQLite database in an application folder. The reasoning why Trilium uses a database instead of plain text files is both performance and some features would be much more difficult to implement such as clones (same note in multiple places in the tree). To find the application folder, simply go to the About window.</FaqItem>
<FaqItem question="Do I need a server to use Trilium?">No, the server allows access via a web browser and manages the synchronization if you have multiple devices. To get started, it's enough to download the desktop application and start using it.</FaqItem>
<FaqItem question="Can I share my database over a network drive?">No, it's generally not a good idea to share a SQLite database over a network drive. Although sometimes it might work, there are chances that the database will get corrupted due to imperfect file locks over a network.</FaqItem>
<FaqItem question="How is my data protected?">By default, notes are not encrypted and can be read directly from the database. Once a note is marked as encrypted, the note is encrypted using AES-128-CBC.</FaqItem>
<FaqItem question="Is there a mobile application?">Currently there is no official mobile application. However, if you have a server instance you can access it using a web browser and even install it as a PWA. For Android, there is an unofficial application called TriliumDroid that even works offline (same as a desktop client).</FaqItem>
<FaqItem question="How well does the application scale with a large amount of notes?">Depending on usage, the application should be able to handle at least 100.000 notes without an issue. Do note that the sync process can sometimes fail if uploading many large files (&gt; 1 GB per file) since Trilium is meant more as a knowledge base application rather than a file store (like NextCloud, for example).</FaqItem>
</Section>
);
}
function FaqItem({ question, children }: { question: string; children: ComponentChildren }) {
return (
<details>
<summary>{question}</summary>
<p>{children}</p>
</details>
)
}

View File

@@ -0,0 +1,9 @@
section.section-404 {
text-align: center;
background: var(--background-color);
}
section.section-404 h2 {
color: var(--brand-3);
margin: 1em;
}

View File

@@ -0,0 +1,10 @@
import Section from "../components/Section";
import "./_404.css";
export function NotFound() {
return (
<Section title="404: Not Found" className="section-404">
The page you were looking for could not be found. Maybe it was deleted or the URL is incorrect.
</Section>
);
}

View File

@@ -1,16 +0,0 @@
<script lang="ts">
import '../app.css';
import Header from './header.svelte';
let { children } = $props();
</script>
<Header />
<main>
{@render children()}
</main>
<footer class="container max-w-screen mx-0 w-full bg-white dark:bg-gray-900 mt-2 py-6 text-sm text-center text-gray-500">
&copy; 2024-2025 <a href="https://github.com/eliandoran" class="text-blue-500 hover:underline">Elian Doran</a> and the <a href="https://github.com/TriliumNext/Notes/graphs/contributors" class="text-blue-500 hover:underline">team</a>. <br/> &copy; 2017-2024 <a href="https://github.com/zadam" class="text-blue-500 hover:underline">zadam</a>.
</footer>

View File

@@ -1,176 +0,0 @@
<script>
import DownloadNow from "./download-now.svelte";
import FeatureBlock from "./feature-block.svelte";
</script>
<svelte:head>
<title>Trilium Notes</title>
<!-- TODO: description?
<meta name="description" content="This is where the description goes for search engines" />
-->
</svelte:head>
<section class="relative overflow-hidden bg-gradient-to-br from-white dark:from-black to-violet-50 dark:to-violet-900">
<!-- Bokeh background circles -->
<div class="absolute inset-0 pointer-events-none z-0">
<div class="absolute w-72 h-72 bg-violet-300 opacity-30 rounded-full blur-3xl top-[-50px] left-[-80px]"></div>
<div class="absolute w-96 h-96 bg-pink-200 opacity-20 rounded-full blur-3xl bottom-[-100px] right-[-60px]"></div>
<div class="absolute w-64 h-64 bg-indigo-200 opacity-20 rounded-full blur-2xl top-[200px] left-[50%] transform -translate-x-1/2"></div>
</div>
<div class="relative z-10 container mx-auto pt-24 pb-24 px-4">
<div class="flex flex-col md:flex-row items-center md:justify-between gap-12">
<!-- Left: Text Content -->
<div class="md:w-1/3">
<h2 class="text-4xl font-bold mb-4 text-gray-900 dark:text-white">Organize Your Thoughts.<br/> Build Your Knowledge.</h2>
<p class="text-lg mb-6 text-gray-700 dark:text-gray-300">
Trilium Notes helps you build and organize complex personal knowledge bases effortlessly.
Its unique tree structure, rich editing tools, and powerful search features make managing your information intuitive and flexible.
<!-- TODO: remove the squiggly autocorrect lines in the screenshot!! -->
<!-- TODO: dark mode screenshot -->
</p>
<div class="flex items-center gap-6">
<DownloadNow big />
<a href="/download" class="font-medium text-violet-700 hover:underline">
More platforms
</a>
</div>
</div>
<!-- Right: Screenshot -->
<div class="md:w-2/3">
<img src="screenshots/desktop-win.png" alt="Screenshot of the app on desktop Windows" class="w-full rounded-xl shadow-lg">
</div>
</div>
</div>
</section>
<section class="mt-20 max-w-6xl mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-12">Beyond Text: Smarter Note Types</h2>
<div class="grid md:grid-cols-2 gap-10">
<FeatureBlock
imgSrc="/note-types/canvas.png"
imgAlt="Canvas Note Screenshot"
title="Canvas Notes"
text="Draw and arrange elements freely using an Excalidraw-powered canvas — ideal for diagrams, sketches, and visual planning."
/>
<FeatureBlock
imgSrc="/note-types/mermaid.png"
imgAlt="Mermaid Diagram Screenshot"
title="Mermaid Diagrams"
text="Render flowcharts, Gantt charts, and sequence diagrams with Mermaid markdown syntax directly in your notes."
/>
<FeatureBlock
imgSrc="/note-types/geo-map.png"
imgAlt="Geo Map Screenshot"
title="Geo Maps"
text="Plot locations and GPX tracks to visualize geography-linked notes and movement patterns on interactive maps."
/>
<FeatureBlock
imgSrc="/note-types/mind-map.png"
imgAlt="Mind Map Screenshot"
title="Mind Maps"
text="Organize ideas visually using a drag-and-drop mind map editor powered by Mind Elixir."
/>
</div>
<h2 class="text-3xl font-bold text-center mb-12">Technical Features</h2>
<div class="grid md:grid-cols-2 gap-10">
<FeatureBlock
imgSrc="/technical-features/sync-server.png"
imgAlt="TODO"
title="Synchronization Server"
text="Seamless mirroring of changes acroll all devices."
/>
<FeatureBlock
imgSrc="/technical-features/cross-platform.png"
imgAlt="TODO, maybe some icons"
title="Cross-platform App + Web UI"
text="Use as Electron application or in your browser."
/>
<FeatureBlock
imgSrc="/technical-features/scripting.png"
imgAlt="TODO"
title="Scripting"
text="Custom UI widgets and a REST API for automation."
/>
<FeatureBlock
imgSrc="/technical-features/grafana-metrics.png"
imgAlt="Mind Map Screenshot"
title="Grafana Metrics"
text="Measure database metrics over time."
/>
</div>
</section>
<section class="mt-20 max-w-6xl mx-auto px-4">
<h2 class="text-3xl font-bold text-center mb-12">Feature Highlights</h2>
<div class="grid gap-12 md:grid-cols-2 max-w-4xl mx-auto text-gray-700 dark:text-gray-300">
<!-- Organization & Navigation -->
<div>
<h3 class="flex items-center text-xl font-semibold mb-6 text-violet-700">Organization & Navigation</h3>
<ul class="list-disc list-inside space-y-3">
<li>Arbitrarily deep note tree with cloning support.</li>
<li>Fast navigation, full-text search, and note hoisting.</li>
<li>Note attributes for organization, querying, and scripting.</li>
<li>Seamless note versioning.</li>
</ul>
</div>
<!-- Editing & Content -->
<div>
<h3 class="flex items-center text-xl font-semibold mb-6 text-violet-700">Editing & Content</h3>
<ul class="list-disc list-inside space-y-3">
<li>Rich WYSIWYG editor with tables, images, math, and markdown autoformat.</li>
<li>Source code editing with syntax highlighting.</li>
<li>Evernote and Markdown import/export.</li>
<li>Web Clipper for easy saving of web content.</li>
</ul>
</div>
<!-- Security & Sync -->
<div>
<h3 class="flex items-center text-xl font-semibold mb-6 text-violet-700">Security & Sync</h3>
<ul class="list-disc list-inside space-y-3">
<li>Direct OpenID and TOTP integration for secure login.</li>
<li>Strong note encryption with per-note granularity.</li>
<li>Sharing notes publicly on the internet.</li>
</ul>
</div>
<!-- Advanced & Customization -->
<div>
<h3 class="flex items-center text-xl font-semibold mb-6 text-violet-700">Advanced & Customization</h3>
<ul class="list-disc list-inside space-y-3">
<li>Relation maps and link maps to visualize notes.</li>
<li>Touch-optimized mobile frontend and dark/user themes.</li>
<li>Customizable UI with sidebar buttons and user widgets.</li>
<li>Scales efficiently beyond 100,000 notes.</li>
</ul>
</div>
</div>
</section>
<section class="bg-violet-50 dark:bg-black py-16 mt-24">
<div class="container mx-auto text-center px-4">
<h2 class="text-3xl font-bold mb-4">Ready to get started with Trilium Notes?</h2>
<p class="text-lg text-gray-700 dark:text-gray-200 mb-8">Build your personal knowledge base with powerful features and full privacy.</p>
<div class="flex justify-center gap-6">
<a href="download" class="py-3 px-6 bg-violet-600 text-white font-semibold rounded-full shadow hover:bg-violet-700 focus:outline-none focus:ring focus:ring-violet-400 focus:ring-opacity-75">
Download Now
</a>
</div>
</div>
</section>

View File

@@ -1 +0,0 @@
<a href="/demo/paraglide">paraglide</a>

View File

@@ -1,15 +0,0 @@
<script lang="ts">
import { setLocale } from '$lib/paraglide/runtime';
import { page } from '$app/state';
import { goto } from '$app/navigation';
import { m } from '$lib/paraglide/messages.js';
</script>
<h1>{m.hello_world({ name: 'SvelteKit User' })}</h1>
<div>
<button onclick={() => setLocale('en')}>en</button>
</div><p>
If you use VSCode, install the <a href="https://marketplace.visualstudio.com/items?itemName=inlang.vs-code-extension" target="_blank">Sherlock i18n extension</a> for a better i18n experience.
</p>

View File

@@ -1,18 +0,0 @@
<script>
import { getRecommendedDownload } from "$lib/download-helper";
export let big = false;
const { url, platform, architecture } = getRecommendedDownload();
</script>
{#if url}
<a href="{url}"
class:text-xl={big}
class:py-4={big}
class="py-2 px-5 bg-violet-600 text-white font-semibold rounded-xl shadow-md hover:bg-violet-700 focus:outline-none focus:ring focus:ring-violet-400 focus:ring-opacity-75">
Download now
<span class="text-sm text-gray-300">
({platform} {architecture})
</span>
</a>
{/if}

View File

@@ -1,65 +0,0 @@
<script lang="ts">
import type { Platform } from "$lib/download-helper";
import { downloadMatrix, getArchitecture } from "$lib/download-helper";
import DownloadCard from "./download-card.svelte";
let architectures = ["x64", "arm64"] as const;
let architecture = getArchitecture();
</script>
<svelte:head>
<title>Trilium Notes: Download</title>
<!-- TODO: description?
<meta name="description" content="This is where the description goes for search engines" />
-->
</svelte:head>
<div class="bg-gray-50 dark:bg-black py-20">
<section class="max-w-6xl mx-auto px-4">
<h2 class="text-4xl font-bold text-center text-gray-900 dark:text-white mb-12">Download the desktop application</h2>
<!-- Architecture pill selector -->
<div class="col-span-3 flex justify-center items-center gap-3 mb-6">
<span class="text-gray-600 dark:text-gray-300 font-medium mr-2">Architecture:</span>
<div class="inline-flex bg-violet-100 rounded-full shadow p-1">
{#each architectures as arch}
<button class="py-2 px-6 rounded-full font-semibold focus:outline-none transition
text-violet-700 border-violet-700
aria-pressed:bg-violet-700 aria-pressed:text-violet-100
" aria-pressed={architecture === arch} on:click={() => architecture = arch}>
{arch}
</button>
{/each}
</div>
</div>
<div class="grid md:grid-cols-3 gap-10">
{#each Object.entries(downloadMatrix.desktop) as [platformId, platform]}
{@const textColor = (platformId === "windows" ? "text-blue-600" : platformId === "linux" ? "text-violet-600" : "text-gray-800 dark:text-gray-100")}
{@const bgColor = (platformId === "windows" ? "bg-blue-600" : platformId === "linux" ? "bg-violet-600" : "bg-gray-800")}
{@const hoverColor = (platformId === "windows" ? "hover:bg-blue-700" : platformId === "linux" ? "hover:bg-violet-700" : "hover:bg-gray-900")}
<DownloadCard app="desktop"
{textColor} {bgColor} {hoverColor}
{platform} {architecture} platformId={platformId as Platform} />
{/each}
</div>
</section>
<section class="max-w-4xl mx-auto px-4 mt-10">
<h2 class="text-3xl font-bold text-center text-gray-900 dark:text-white mb-8">Set up a server for access on multiple devices</h2>
<div class="grid md:grid-cols-2 gap-10">
{#each Object.entries(downloadMatrix.server) as [platformId, platform]}
{@const textColor = (platformId === "linux" ? "text-violet-600" : "text-gray-800 dark:text-gray-100")}
{@const bgColor = (platformId === "linux" ? "bg-violet-600" : "bg-gray-800")}
{@const hoverColor = (platformId === "linux" ? "hover:bg-violet-700" : "hover:bg-gray-900")}
<DownloadCard app="server"
{textColor} {bgColor} {hoverColor}
{platform} {architecture} platformId={platformId as Platform} />
{/each}
</div>
</section>
<!-- TODO: mention mobile support here? (alpha Android app / mobile web view) -->
</div>

View File

@@ -1,31 +0,0 @@
<script lang="ts">
import { buildDownloadUrl, type Architecture, type DownloadMatrixEntry, type Platform, type App } from "$lib/download-helper";
export let app: App = "desktop";
export let platformId: Platform;
export let platform: DownloadMatrixEntry;
export let textColor: string;
export let bgColor: string;
export let hoverColor: string;
export let architecture: Architecture | null = null;
const recommended = Object.entries(platform.downloads).find((e) => e[1].recommended);
</script>
<div class="bg-white dark:bg-gray-900 border border-gray-200 rounded-2xl shadow-lg p-8 flex flex-col items-start">
<h3 class="text-2xl font-semibold {textColor} mb-2">{typeof platform.title === "object" ? platform.title[architecture] : platform.title}</h3>
<p class="text-gray-700 dark:text-gray-200 mb-12">{typeof platform.title === "object" ? platform.description[architecture] : platform.description}</p>
<div class="space-y-2 mt-auto w-full">
{#if recommended}
<a href={buildDownloadUrl(app, platformId as Platform, recommended[0], architecture)} class="mt-auto block text-center {bgColor} {hoverColor} text-white font-medium py-2 px-5 rounded-full shadow transition">
{recommended[1].name}
</a>
{/if}
<div class="flex flex-wrap justify-center gap-4 text-sm {textColor} mt-2">
{#each Object.entries(platform.downloads).filter((e) => !e[1].recommended) as [format, download]}
<a href={buildDownloadUrl(app, platformId as Platform, format, architecture)} class="hover:underline block">
{download.name}
</a>
{/each}
</div>
</div>
</div>

View File

@@ -1,14 +0,0 @@
<script>
export let imgSrc = "/404.png";
export let imgAlt = "screenshot";
export let title = "title";
export let text = "text";
</script>
<div class="bg-white dark:bg-gray-900 rounded-xl shadow overflow-hidden">
<img src="{imgSrc}" alt="{imgAlt}" class="w-full h-56 object-cover object-top">
<div class="p-6">
<h3 class="text-xl font-semibold mb-2">{title}</h3>
<p class="text-gray-600 dark:text-gray-300">{text}</p>
</div>
</div>

View File

@@ -1,23 +0,0 @@
<script>
import DownloadNow from "./download-now.svelte";
</script>
<header class="header bg-white dark:bg-gray-900 sticky dark:text-white top-0 z-50 shadow">
<div class="container mx-auto flex items-center py-4">
<a href="/" class="flex items-center gap-x-2 w-100">
<img src="icon-color.svg" alt="Trilium Notes Logo" class="w-12 h-12">
<span class="text-2xl">Trilium Notes</span>
</a>
<div class="group w-full">
<nav class="header-nav">
<ul class="flex items-center justify-end gap-4">
<li><a href="/">User Guide</a></li>
<li><a href="/">Technical Guide</a></li>
<li><a href="/" class="text-violet-500">Support us</a></li>
<li><DownloadNow /></li>
</ul>
</nav>
</div>
</div>
</header>

110
apps/website/src/style.css Normal file
View File

@@ -0,0 +1,110 @@
:root {
--background-color: #fff;
--foreground-color: black;
--muted-color: #353535;
--card-background-color: white;
--card-box-shadow: 0 0 3px rgba(0, 0, 0, 0.25);
--header-background-color: rgba(255, 255, 255, 0.75);
--brand-1: #e47b19;
--brand-2: #4fa52b;
--brand-3: #e33f3b;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-color: #fff;
--background-color: #0a0e14;
--muted-color: #cacaca;
--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);
}
}
html,
body {
margin: 0;
line-height: 1.5;
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
min-height: 100vh;
}
main {
min-height: calc(100vh - 80px);
display: flex;
flex-direction: column;
}
body {
font-family: sans-serif;
background: var(--background-color);
color: var(--foreground-color);
}
a {
color: var(--brand-3);
}
.content-wrapper {
max-width: 1200px;
width: 100%;
margin: auto;
}
section {
padding: 3em 0;
flex-grow: 1;
display: flex;
justify-content: center;
align-items: stretch;
}
section h2 {
text-align: center;
font-weight: 100;
margin-top: 0;
margin-bottom: 2em;
}
img {
width: 100%;
height: auto;
}
.card {
border: 0;
box-shadow: var(--card-box-shadow);
background-color: var(--card-background-color);
border-radius: 16px;
overflow: hidden;
}
.card-content {
margin: 0;
padding: 1em;
color: var(--muted-color);
}
.card h3 {
font-size: 1.1rem;
font-weight: 300;
margin: 0;
color: var(--foreground-color);
}
.card > .image {
height: 200px;
object-fit: cover;
}
.grid-3-cols {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1em;
}
.grid-2-cols {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1em;
}