diff --git a/website/scripts/sync-brand.mjs b/website/scripts/sync-brand.mjs index a8e8325..674f94e 100644 --- a/website/scripts/sync-brand.mjs +++ b/website/scripts/sync-brand.mjs @@ -12,6 +12,8 @@ const out = join(dirname(fileURLToPath(import.meta.url)), '..', 'static', 'brand const files = [ 'svg/outprint-lockup.svg', 'svg/outprint-lockup-dark.svg', + 'svg/outprint-banner.svg', + 'svg/outprint-banner-dark.svg', 'favicon/favicon.svg', 'favicon/favicon.ico', 'favicon/apple-touch-icon.png', diff --git a/website/src/pages/index.js b/website/src/pages/index.js index 3a7f8c9..6862f16 100644 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -1,11 +1,59 @@ import React from 'react'; -import Layout from '@theme/Layout'; import Link from '@docusaurus/Link'; +import Layout from '@theme/Layout'; +import ThemedImage from '@theme/ThemedImage'; +import useBaseUrl from '@docusaurus/useBaseUrl'; + import styles from './index.module.css'; -// The five sections of the docs (issue #52). One word, one line each. -// docs/README.md keeps the same list as a plain table for GitHub. -const sections = [ +const METADATA_EXAMPLE = [ + ['type', 'letter'], + ['subject', 'Spring plant sale'], + ['reference', 'PS-2026-03'], + ['recipient', null], + ['', ' - Ada Example'], + ['', ' - 1 Sample Lane'], + ['', ' - 12345 Exampleton'], + ['closing', 'With best wishes'], +]; + +const STEPS = [ + { + title: 'Pick a Template', + text: 'A Template provides the look and structure: a letter, a report, or your own design in LaTeX.', + }, + { + title: 'Bind it to a Collection', + text: 'A Collection admin pairs the Template with a Configuration that holds the organisation name, logo and colours.', + }, + { + title: 'Write and download', + text: 'Authors fill a few fields at the top of a Document and click Download PDF.', + }, +]; + +const FEATURES = [ + { + title: 'No Outline fork', + text: 'A small reverse proxy adds the Download PDF button. Outline itself stays untouched and upgradable.', + }, + { + title: 'Real typesetting', + text: 'Pandoc and LuaLaTeX turn the Document into a PDF, so letters and reports look like they were set, not exported.', + }, + { + title: 'Content apart from branding', + text: 'Names, logos and colours live in the Configuration. Authors write content and cannot override them.', + }, + { + title: 'Renders in a sandbox', + text: 'The Worker that runs LaTeX has no network and no secrets. It only turns a bundle into a PDF.', + }, +]; + +// The five sections of the docs. docs/README.md keeps the same list as a +// plain table for GitHub. +const SECTIONS = [ {to: '/write/', title: 'Write', line: 'Make a PDF from a document, and fix a message.'}, {to: '/configure/', title: 'Configure', line: 'Give a Collection its PDF look.'}, {to: '/deploy/', title: 'Deploy', line: 'Install Outprint next to your own Outline.'}, @@ -13,43 +61,117 @@ const sections = [ {to: '/internals/', title: 'Internals', line: 'How it works, and why it is safe.'}, ]; +function DocumentCard() { + return ( +
+
Top of an Outline document
+
+        
+          ```yaml
+          {'\n'}
+          {METADATA_EXAMPLE.map(([key, value], index) => (
+            
+              {key ? {key}: : null}
+              {value ? {key ? ' ' : ''}{value} : null}
+              {'\n'}
+            
+          ))}
+          ```
+          {'\n'}
+          Thank you for your enquiry ...
+        
+      
+
+ ); +} + export default function Home() { return ( -
-
-

Documentation

-

- Outline documents, -
- typeset as PDF. -

-

- Outprint adds a Download PDF button to your own Outline. Letters and - reports get a letterhead, a footer and a fixed layout. Nobody has to - design anything. -

-
- + + +
+

+ Built to be run by a small team +

+
+ {FEATURES.map((feature) => ( +
+
{feature.title}
+
{feature.text}
+
+ ))} +
+
+ +
+

+ Find your way in +

+ +
); diff --git a/website/src/pages/index.module.css b/website/src/pages/index.module.css index 6220ff5..ba29731 100644 --- a/website/src/pages/index.module.css +++ b/website/src/pages/index.module.css @@ -1,58 +1,220 @@ -/* Landing page. An editorial list instead of a card grid: a calm intro on the - left, five numbered rows on the right. Colours come from the tokens in - custom.css, so both themes follow. Hover and focus move only transform and - opacity. */ +/* Landing page. Uses the --op-* tokens from custom.css, so light and dark + follow the site theme. The folded corner on the document card repeats the + mark in the logo. */ -.page { +.hero { + border-bottom: 1px solid var(--op-border); + padding: clamp(2.5rem, 6vw, 5.5rem) 1rem; +} + +.heroInner { display: grid; - gap: clamp(2.5rem, 6vw, 6rem); - grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); - align-items: start; - max-width: 1180px; + grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr); + gap: clamp(2rem, 5vw, 4.5rem); + align-items: center; + max-width: 1160px; margin: 0 auto; - padding: clamp(3rem, 8vw, 7rem) 1rem clamp(3rem, 8vw, 7rem); } -@media (max-width: 900px) { - .page { - grid-template-columns: minmax(0, 1fr); - } +.banner { + margin: 0 0 1.5rem; + line-height: 0; +} +.banner img { + display: block; + width: min(100%, 440px); + height: auto; } -.kicker { - margin: 0 0 1.25rem; - font-size: 0.8125rem; +.lead { + max-width: 34rem; + margin: 0 0 2rem; + font-size: clamp(1.1rem, 1rem + 0.4vw, 1.3rem); + line-height: 1.6; + color: var(--op-muted-text); +} +.lead strong { + color: var(--op-text); font-weight: 500; - letter-spacing: 0.14em; - text-transform: uppercase; +} + +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} + +.primary, +.secondary { + display: inline-block; + padding: 0.7rem 1.25rem; + border-radius: 6px; + font-weight: 500; + text-decoration: none; + transition: background-color 150ms ease, border-color 150ms ease; +} +.primary { + background: var(--op-accent); + border: 1px solid var(--op-accent); + color: #0b2616; +} +.primary:hover { + background: #52d78c; + border-color: #52d78c; + color: #0b2616; + text-decoration: none; +} +.secondary { + border: 1px solid var(--op-border); + background: var(--op-card); + color: var(--op-text); +} +.secondary:hover { + border-color: var(--op-muted); + color: var(--op-text); + text-decoration: none; +} + +/* The document card */ +.document { + position: relative; + margin: 0; + padding: 1.25rem 1.5rem 1.5rem; + background: var(--op-card); + border: 1px solid var(--op-border); + border-radius: 10px; + clip-path: polygon(0 0, calc(100% - 56px) 0, 100% 56px, 100% 100%, 0 100%); +} +.document::after { + content: ''; + position: absolute; + top: 0; + right: 0; + width: 56px; + height: 56px; + background: var(--op-accent); + clip-path: polygon(0 0, 0 100%, 100% 100%); +} + +.documentCaption { + margin-bottom: 0.75rem; + font-size: 0.875rem; color: var(--op-muted-text); } -.title { +.documentCode { margin: 0; - font-size: clamp(2.25rem, 1.2rem + 3.6vw, 4rem); - line-height: 1.04; - letter-spacing: -0.025em; + padding: 0; + border: 0; + background: transparent; + font-size: 0.9rem; + line-height: 1.7; + overflow-x: auto; +} +.documentCode code { + border: 0; + background: transparent; + padding: 0; } -.title::after { - content: ''; +.fence { + color: var(--op-muted-text); +} +.key { + color: var(--op-link); + font-weight: 500; +} +.value { + color: var(--op-text); +} +.body { + display: inline-block; + margin-top: 0.5rem; + font-family: var(--ifm-font-family-base); + color: var(--op-text); +} + +/* Content sections */ +.section { + max-width: 1160px; + margin: 0 auto; + padding: clamp(2.5rem, 5vw, 4rem) 1rem 0; +} +.section:last-child { + padding-bottom: clamp(3rem, 6vw, 5rem); +} + +.sectionTitle { + max-width: 28rem; + margin: 0 0 1.75rem; + font-size: clamp(1.5rem, 1.2rem + 1vw, 2rem); + line-height: 1.25; +} + +.steps { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1.5rem; + margin: 0; + padding: 0; + list-style: none; + counter-reset: step; +} +.step { + position: relative; + padding-top: 1rem; + border-top: 2px solid var(--op-text); + counter-increment: step; +} +.step::before { + content: counter(step); display: block; - width: 3.5rem; - height: 4px; - margin-top: 1.75rem; - border-radius: 2px; - background: var(--op-accent); + margin-bottom: 0.5rem; + font-size: 2.25rem; + font-weight: 700; + line-height: 1; + color: var(--op-link); +} +.step h3 { + margin: 0 0 0.35rem; + font-size: 1.15rem; +} +.step p { + margin: 0; + max-width: 24rem; + color: var(--op-muted-text); } -.lead { +.features { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 2rem 3rem; + margin: 0; +} +.feature dt { + font-size: 1.1rem; + font-weight: 700; +} +.feature dd { + margin: 0.3rem 0 0; max-width: 30rem; - margin: 1.75rem 0 0; - font-size: 1.125rem; - line-height: 1.6; color: var(--op-muted-text); } +@media (max-width: 996px) { + .heroInner { + grid-template-columns: minmax(0, 1fr); + } + .steps { + grid-template-columns: minmax(0, 1fr); + } + .features { + grid-template-columns: minmax(0, 1fr); + } +} + +/* Documentation sections: numbered rows. The green rule and the arrow move + only transform and opacity. */ .list { margin: 0; padding: 0;