diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1430d80 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,22 @@ +name: Website build + +on: + pull_request: + push: + branches: [master] + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: npm + - run: npm ci + - run: npm run build diff --git a/README.md b/README.md index f3a2225..0becb40 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # Papyrus website -Landing page for the [Papyrus](https://github.com/Eoic/Papyrus) project - a free, open-source e-book reader and library manager for Android, iOS, Windows, macOS, Linux, and Web. +Landing page for the [Papyrus](https://github.com/PapyrusReader/papyrus) project - a free, open-source e-book reader and library manager for Android, iOS, Windows, macOS, Linux, and Web. ## Getting Started ```bash -npm install +npm ci npm run dev ``` This starts a local server at `http://localhost:8090` with live SCSS recompilation. + +Build deployable assets with `npm run build`; output is written to `build/`. diff --git a/index.html b/index.html index cbfa47b..230f04d 100644 --- a/index.html +++ b/index.html @@ -43,7 +43,7 @@ Features Platforms Open source - Docs @@ -150,7 +150,7 @@

Your books, your data, ev
- 7 e-book formats + EPUB & PDF reading
@@ -193,7 +193,7 @@

No internet required

Your data stays yours

No analytics. No tracking. No account required. Store books locally, on your own - server, or on any cloud provider you trust.

+ server. Additional cloud provider integrations are planned.

@@ -233,10 +233,10 @@

Organize your way

Read comfortably anywhere

@@ -306,7 +306,7 @@

One app. Every platform.

@@ -318,7 +318,7 @@

One app. Every platform.

Store your books where you want

-

Local storage by default. Sync through your own server, or connect any cloud provider. +

Local storage by default. Sync through your Papyrus server; additional cloud providers are planned.

@@ -338,23 +338,23 @@

Store your books where you want

- Google Drive + Google Drive (planned)
- WebDAV + WebDAV (planned)
- S3-compatible + S3-compatible (planned)
- + Learn more about self-hosting @@ -385,11 +385,11 @@

Open source. Transparent. C @@ -404,20 +404,20 @@

Download Features Platforms - Documentation @@ -432,7 +432,6 @@ - diff --git a/js/main.js b/js/main.js index 609cab7..66419fb 100644 --- a/js/main.js +++ b/js/main.js @@ -2,74 +2,18 @@ 'use strict'; const THEMES = { - 'light-gold': { metaColor: '#FDFAF5', qrDot: '#2D2A26' }, - 'dark-gold': { metaColor: '#1A1814', qrDot: '#2D2A26' }, - 'light-purple': { metaColor: '#FAFAFE', qrDot: '#1C1B1F' }, - 'dark-purple': { metaColor: '#151318', qrDot: '#1C1B1F' }, + 'light-gold': { metaColor: '#FDFAF5' }, + 'dark-gold': { metaColor: '#1A1814' }, + 'light-purple': { metaColor: '#FAFAFE' }, + 'dark-purple': { metaColor: '#151318' }, }; const DEFAULT_THEME = 'light-gold'; - const VERSION = '1.2.0'; - const BASE = `https://github.com/Eoic/Papyrus/releases/download/v${VERSION}`; - - const PLATFORMS = { - android: { - name: 'Android', - downloadLabel: 'Download APK', - downloadUrl: `${BASE}/papyrus-v${VERSION}-android-arm64.apk`, - fileName: `papyrus-v${VERSION}-android-arm64.apk`, - fileSize: '48.3 MB', - showQr: true, - qrUrl: `${BASE}/papyrus-v${VERSION}-android-arm64.apk`, - store: { name: 'Google Play', icon: 'fa-brands fa-google-play', url: '#' }, - }, - ios: { - name: 'iOS', - downloadLabel: 'Download IPA', - downloadUrl: `${BASE}/papyrus-v${VERSION}-ios-arm64.ipa`, - fileName: `papyrus-v${VERSION}-ios-arm64.ipa`, - fileSize: '52.1 MB', - showQr: true, - qrUrl: `${BASE}/papyrus-v${VERSION}-ios-arm64.ipa`, - store: { name: 'App Store', icon: 'fa-brands fa-app-store', url: '#' }, - }, - windows: { - name: 'Windows', - downloadLabel: 'Download ZIP', - downloadUrl: `${BASE}/papyrus-v${VERSION}-windows-x64.zip`, - fileName: `papyrus-v${VERSION}-windows-x64.zip`, - fileSize: '62.1 MB', - showQr: false, - store: null, - }, - macos: { - name: 'macOS', - downloadLabel: 'Download DMG', - downloadUrl: `${BASE}/papyrus-v${VERSION}-macos-universal.dmg`, - fileName: `papyrus-v${VERSION}-macos-universal.dmg`, - fileSize: '71.4 MB', - showQr: false, - store: { name: 'Mac App Store', icon: 'fa-brands fa-app-store', url: '#' }, - }, - linux: { - name: 'Linux', - downloadLabel: 'Download tar.gz', - downloadUrl: `${BASE}/papyrus-v${VERSION}-linux-x64.tar.gz`, - fileName: `papyrus-v${VERSION}-linux-x64.tar.gz`, - fileSize: '58.7 MB', - showQr: false, - store: null, - }, - web: { - name: 'Web', - downloadLabel: 'Download ZIP', - downloadUrl: `${BASE}/papyrus-v${VERSION}-web.zip`, - fileName: `papyrus-v${VERSION}-web.zip`, - fileSize: '24.5 MB', - showQr: false, - store: null, - }, - }; + const RELEASES_URL = 'https://github.com/PapyrusReader/client/releases'; + const PLATFORMS = Object.fromEntries([ + ['android', 'Android'], ['ios', 'iOS'], ['windows', 'Windows'], + ['macos', 'macOS'], ['linux', 'Linux'], ['web', 'Web'], + ].map(([key, name]) => [key, { name }])); const getCurrentTheme = () => document.documentElement.getAttribute('data-theme') ?? DEFAULT_THEME; @@ -94,13 +38,7 @@ document.documentElement.removeAttribute('data-theme-transitioning'); }, 350); - if (currentPlatform && PLATFORMS[currentPlatform]?.showQr) { - const container = document.querySelector(`.platform-qr-code[data-qr-target="${currentPlatform}"]`); - if (container) { - container.replaceChildren(); - generateQrCode(currentPlatform); - } - } + }; const detectPlatform = () => { @@ -136,98 +74,35 @@ const detectedPlatform = detectPlatform(); let currentPlatform = null; - const buildStoreBadge = (store) => { - if (!store) return null; - const badge = el('a', 'platform-store-badge', { href: store.url }); - badge.appendChild(faIcon(store.icon)); - const label = document.createElement('span'); - label.textContent = store.name; - badge.appendChild(label); - return badge; - }; - const buildPanelEl = (key) => { const cfg = PLATFORMS[key]; if (!cfg) return null; - const inner = el('div', cfg.showQr - ? 'platform-details-inner platform-details-inner--with-qr' - : 'platform-details-inner'); - + const inner = el('div', 'platform-details-inner'); const left = el('div', 'platform-details-left'); - const header = el('div', 'platform-details-header'); const title = el('h3', 'platform-details-title'); title.textContent = cfg.name; header.appendChild(title); - const ver = el('span', 'platform-details-version'); - ver.textContent = `v${VERSION}`; - header.appendChild(ver); left.appendChild(header); const actions = el('div', 'platform-details-actions'); const actionsRow = el('div', 'platform-actions-row'); - - const dlBtn = el('a', 'platform-download-btn', { href: cfg.downloadUrl, download: '' }); - dlBtn.appendChild(faIcon('fa-solid fa-download')); - const dlSpan = document.createElement('span'); - dlSpan.textContent = cfg.downloadLabel; - dlBtn.appendChild(dlSpan); - actionsRow.appendChild(dlBtn); - - const storeBadge = buildStoreBadge(cfg.store); - - if (storeBadge) - actionsRow.appendChild(storeBadge); - + const releases = el('a', 'platform-download-btn', { href: RELEASES_URL }); + releases.appendChild(faIcon('fa-brands fa-github')); + const label = document.createElement('span'); + label.textContent = 'Check available releases'; + releases.appendChild(label); + actionsRow.appendChild(releases); actions.appendChild(actionsRow); - const meta = el('span', 'platform-download-meta'); - meta.textContent = `${cfg.fileName} \u00B7 ${cfg.fileSize}`; + meta.textContent = 'Platform support is under development. Release builds are not published yet.'; actions.appendChild(meta); left.appendChild(actions); inner.appendChild(left); - - if (cfg.showQr) { - const qrWrap = el('div', 'platform-details-qr'); - const qrBox = el('div', 'platform-qr-code', { 'data-qr-target': key }); - qrWrap.appendChild(qrBox); - const qrLabel = el('span', 'platform-qr-label'); - qrLabel.textContent = 'Scan to download'; - qrWrap.appendChild(qrLabel); - inner.appendChild(qrWrap); - } - return inner; }; - const generateQrCode = (key) => { - if (typeof QRCodeStyling === 'undefined') return; - - const cfg = PLATFORMS[key]; - if (!cfg?.qrUrl) return; - - const container = document.querySelector(`.platform-qr-code[data-qr-target="${key}"]`); - if (!container) return; - - const theme = getCurrentTheme(); - const { qrDot } = THEMES[theme] ?? {}; - - const qr = new QRCodeStyling({ - width: 140, - height: 140, - type: 'svg', - data: cfg.qrUrl, - dotsOptions: { color: qrDot ?? '#2D2A26', type: 'rounded' }, - backgroundOptions: { color: '#FFFFFF' }, - cornersSquareOptions: { type: 'extra-rounded' }, - cornersDotOptions: { type: 'dot' }, - qrOptions: { errorCorrectionLevel: 'M' }, - }); - - qr.append(container); - }; - const collapsePanel = () => { if (!currentPlatform) return; @@ -263,9 +138,6 @@ document.querySelector(`.platform-card[data-platform="${key}"]`) ?.setAttribute('aria-expanded', 'true'); - if (PLATFORMS[key]?.showQr) { - generateQrCode(key); - } }; const onScroll = () => nav.classList.toggle('scrolled', window.scrollY > 20); diff --git a/scss/_platforms.scss b/scss/_platforms.scss index 577388d..058f843 100644 --- a/scss/_platforms.scss +++ b/scss/_platforms.scss @@ -84,12 +84,6 @@ position: relative; } -.platform-details-inner--with-qr { - display: flex; - align-items: stretch; - justify-content: space-between; -} - .platform-details-inner::before { content: ''; position: absolute; @@ -106,7 +100,6 @@ flex-direction: column; justify-content: center; gap: var(--space-xl); - padding-right: var(--space-2xl); } .platform-details-header { @@ -123,12 +116,6 @@ margin: 0; } -.platform-details-version { - font-size: 0.875rem; - color: var(--color-text-tertiary); - font-weight: 500; -} - .platform-details-actions { display: flex; flex-direction: column; @@ -173,59 +160,6 @@ line-height: 1.5; } -.platform-store-badge { - display: inline-flex; - align-items: center; - gap: var(--space-sm); - padding: 0.75rem 1.5rem; - border: 1px solid var(--color-border); - border-radius: var(--radius-md); - font-size: 0.9375rem; - font-weight: 500; - color: var(--color-text); - background: var(--color-surface); - text-decoration: none; - transition: border-color var(--duration-fast); -} - -.platform-store-badge:hover { - border-color: var(--color-accent); -} - -.platform-store-badge > i { - font-size: 1.125rem; - color: var(--color-text-secondary); -} - -.platform-details-qr { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: var(--space-sm); - padding-left: var(--space-2xl); - border-left: 1px solid var(--color-border-light); -} - -.platform-qr-code { - width: 148px; - height: 148px; - background: #fff; - border: 1px solid var(--color-border-light); - border-radius: var(--radius-md); - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; - padding: 4px; -} - -.platform-qr-label { - font-size: 0.75rem; - color: var(--color-text-tertiary); - text-align: center; -} - .platforms-noscript { text-align: center; padding: var(--space-xl) 0; @@ -247,29 +181,6 @@ grid-template-columns: repeat(3, 1fr); } - .platform-details-inner--with-qr { - flex-direction: column; - } - - .platform-details-left { - padding-right: 0; - padding-bottom: var(--space-xl); - } - - .platform-details-qr { - flex-direction: row; - gap: var(--space-md); - align-items: center; - padding-left: 0; - padding-top: var(--space-xl); - border-left: none; - border-top: 1px solid var(--color-border-light); - } - - .platform-qr-code { - width: 100px; - height: 100px; - } } @media (max-width: 599px) { @@ -305,17 +216,4 @@ justify-content: center; } - .platform-store-badge { - justify-content: center; - } - - .platform-details-qr { - flex-direction: column; - align-items: center; - } - - .platform-qr-code { - width: 140px; - height: 140px; - } }