feat(website): port download page

This commit is contained in:
Elian Doran 2025-09-27 00:46:51 +03:00
parent 3c2263db86
commit 818efe7fb0
No known key found for this signature in database
7 changed files with 111 additions and 23 deletions

View File

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

View File

@ -5,6 +5,7 @@ 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';
export function App() {
return (
@ -14,6 +15,7 @@ export function App() {
<Router>
<Route path="/" component={Home} />
<Route default component={NotFound} />
<Route path="/download" component={Download} />
</Router>
</main>
<Footer />

View File

@ -0,0 +1,40 @@
.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;
}

View File

@ -0,0 +1,51 @@
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 [ arch, setArch ] = useState(getArchitecture());
return (
<>
<Section title="Download the desktop application">
<div className="grid-3-cols download-desktop">
{Object.entries(downloadMatrix.desktop).map(entry => <DownloadCard app="desktop" arch={arch} 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={arch} 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

@ -99,24 +99,6 @@ section:nth-of-type(2n+1) {
background: linear-gradient(135deg, rgba(228, 123, 25, 0.08), rgba(79, 165, 43, 0.08));
}
.benefits-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1em;
}
.benefits-container .card {
padding: 1em;
}
.note-types-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1em;
}
.collections-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1em;
}

View File

@ -37,7 +37,7 @@ function HeroSection() {
function BenefitsSection() {
return (
<Section className="benefits" title="Benefits">
<div className="benefits-container">
<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
@ -63,7 +63,7 @@ function BenefitsSection() {
function NoteTypesSection() {
return (
<Section className="note-types" title="Note types">
<div class="note-types-container">
<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>
@ -79,7 +79,7 @@ function NoteTypesSection() {
function CollectionsSection() {
return (
<Section className="collections" title="Collections">
<div className="collections-container">
<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>

View File

@ -89,4 +89,16 @@ footer {
.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;
}