diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1ff29b..bf51aef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,3 +22,33 @@ jobs: - run: npm run check - run: npx playwright install --with-deps chromium - run: npm run test:e2e + + deploy-pages: + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: test-and-build + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: npm + - run: npm ci + - run: npm run build + env: + GITHUB_PAGES: 'true' + - uses: actions/configure-pages@v5 + - uses: actions/upload-pages-artifact@v4 + with: + path: dist + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/README.md b/README.md index f38eba0..881a831 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,10 @@ Trajectory helps people record a few facts about each day, review a week, see ch **Vue 3 · TypeScript · Pinia · Dexie · ECharts · PWA** +**[Open the live demo](https://dmitryaf.github.io/trajectory/)** · [Source code](https://github.com/Dmitryaf/trajectory) + +The demo uses synthetic data and stores later changes only in this browser. It does not require an account or connect to the production service. + The main flow is small: record what mattered today, review a completed week, look at longer-term changes, and choose what to do next. Every field is optional. Missing entries stay missing instead of being replaced with guesses. ## Why Trajectory @@ -111,6 +115,10 @@ npm.cmd run dev The synthetic data asset is generated automatically before development, production builds, and Playwright runs. +## Deployment + +GitHub Actions publishes the validated demo build to GitHub Pages after changes reach `main`. The deployed app uses the `/trajectory/` base path and hash-based routes so that every screen remains available on static hosting. + ## Public and production editions This repository contains an interactive public showcase of Trajectory. It presents the three core local-first scenarios — Today, Week, and History — while production authentication, cloud synchronization, the monthly review, journals, settings, backend infrastructure, private data, internal documentation, and private development history remain outside this repository. diff --git a/e2e/showcase.e2e.ts b/e2e/showcase.e2e.ts index 1464bfd..de9f73c 100644 --- a/e2e/showcase.e2e.ts +++ b/e2e/showcase.e2e.ts @@ -52,7 +52,7 @@ test('persists a daily note in IndexedDB across reloads', async ({ page }) => { test('navigates through Week and Trends and captures representative analytics', async ({ page }) => { await page.setViewportSize({ width: 1440, height: 900 }); await page.emulateMedia({ reducedMotion: 'reduce' }); - await page.goto(`/week?week=${completedWeek()}`); + await page.goto(`/#/week?week=${completedWeek()}`); await expect(page.getByRole('heading', { name: 'Неделя', level: 1 })).toBeVisible(); await expect(page.getByRole('heading', { name: 'На что обратить внимание' })).toBeVisible(); await settleScreenshot(page); diff --git a/index.html b/index.html index e267b58..87a7648 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ - + Траектория diff --git a/src/main.ts b/src/main.ts index 5e76a80..6636ed6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,6 @@ import { createApp } from 'vue'; import { createPinia } from 'pinia'; -import { createRouter, createWebHistory } from 'vue-router'; +import { createRouter, createWebHashHistory } from 'vue-router'; import { registerSW } from 'virtual:pwa-register'; import App from './App.vue'; import './style.css'; @@ -17,7 +17,7 @@ window.addEventListener('vite:preloadError', (event) => { registerSW({ immediate: true }); const router = createRouter({ - history: createWebHistory(), + history: createWebHashHistory(import.meta.env.BASE_URL), scrollBehavior(to) { if (to.hash) return { el: to.hash, top: 88, behavior: 'smooth' }; return { top: 0 }; diff --git a/vite.config.ts b/vite.config.ts index d65aed7..8c18c60 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,7 +2,10 @@ import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import { VitePWA } from 'vite-plugin-pwa'; +const base = process.env.GITHUB_PAGES === 'true' ? '/trajectory/' : '/'; + export default defineConfig({ + base, plugins: [ vue(), VitePWA({ @@ -15,18 +18,19 @@ export default defineConfig({ theme_color: '#11182b', background_color: '#f4f6fb', display: 'standalone', - start_url: '/', + start_url: base, + scope: base, lang: 'ru', icons: [ - { src: '/icons/icon-192.png', sizes: '192x192', type: 'image/png' }, - { src: '/icons/icon-512.png', sizes: '512x512', type: 'image/png' }, - { src: '/icons/icon-512-maskable.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' }, + { src: `${base}icons/icon-192.png`, sizes: '192x192', type: 'image/png' }, + { src: `${base}icons/icon-512.png`, sizes: '512x512', type: 'image/png' }, + { src: `${base}icons/icon-512-maskable.png`, sizes: '512x512', type: 'image/png', purpose: 'maskable' }, ], }, workbox: { cleanupOutdatedCaches: true, - navigateFallback: '/index.html', - navigateFallbackDenylist: [/^\/api(?:\/|$)/, /^\/assets(?:\/|$)/], + navigateFallback: `${base}index.html`, + navigateFallbackDenylist: [/\/api(?:\/|$)/, /\/assets(?:\/|$)/], globPatterns: ['**/*.{js,css,html,json,svg,png,woff2}'], }, }),