@linguanahq/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/dist/index.js +1543 -0
- package/dist/templates/blog/react/.env.example +15 -0
- package/dist/templates/blog/react/ASSETS.md +1 -0
- package/dist/templates/blog/react/DEPLOY.md +23 -0
- package/dist/templates/blog/react/LICENSE +21 -0
- package/dist/templates/blog/react/README.md +36 -0
- package/dist/templates/blog/react/_gitignore +11 -0
- package/dist/templates/blog/react/index.html +2 -0
- package/dist/templates/blog/react/linguana.json +10 -0
- package/dist/templates/blog/react/package.json +34 -0
- package/dist/templates/blog/react/public/assets/scene-1.svg +1 -0
- package/dist/templates/blog/react/public/assets/scene-2.svg +1 -0
- package/dist/templates/blog/react/public/assets/scene-3.svg +1 -0
- package/dist/templates/blog/react/public/assets/scene-4.svg +1 -0
- package/dist/templates/blog/react/public/assets/scene-5.svg +1 -0
- package/dist/templates/blog/react/public/assets/scene-6.svg +1 -0
- package/dist/templates/blog/react/src/App.tsx +465 -0
- package/dist/templates/blog/react/src/Copy.tsx +322 -0
- package/dist/templates/blog/react/src/demo-messages.ts +221 -0
- package/dist/templates/blog/react/src/i18n.ts +62 -0
- package/dist/templates/blog/react/src/main.tsx +11 -0
- package/dist/templates/blog/react/src/messages.ts +71 -0
- package/dist/templates/blog/react/src/model.ts +128 -0
- package/dist/templates/blog/react/src/styles.css +1159 -0
- package/dist/templates/blog/react/src/vite-env.d.ts +1 -0
- package/dist/templates/blog/react/tsconfig.json +23 -0
- package/dist/templates/blog/react/vite.config.ts +36 -0
- package/dist/templates/blog/react/wrangler.jsonc +8 -0
- package/dist/templates/blog/solidjs/.env.example +15 -0
- package/dist/templates/blog/solidjs/ASSETS.md +1 -0
- package/dist/templates/blog/solidjs/DEPLOY.md +23 -0
- package/dist/templates/blog/solidjs/LICENSE +21 -0
- package/dist/templates/blog/solidjs/README.md +36 -0
- package/dist/templates/blog/solidjs/_gitignore +11 -0
- package/dist/templates/blog/solidjs/index.html +2 -0
- package/dist/templates/blog/solidjs/linguana.json +10 -0
- package/dist/templates/blog/solidjs/package.json +31 -0
- package/dist/templates/blog/solidjs/public/assets/scene-1.svg +1 -0
- package/dist/templates/blog/solidjs/public/assets/scene-2.svg +1 -0
- package/dist/templates/blog/solidjs/public/assets/scene-3.svg +1 -0
- package/dist/templates/blog/solidjs/public/assets/scene-4.svg +1 -0
- package/dist/templates/blog/solidjs/public/assets/scene-5.svg +1 -0
- package/dist/templates/blog/solidjs/public/assets/scene-6.svg +1 -0
- package/dist/templates/blog/solidjs/src/App.tsx +457 -0
- package/dist/templates/blog/solidjs/src/Copy.tsx +322 -0
- package/dist/templates/blog/solidjs/src/demo-messages.ts +221 -0
- package/dist/templates/blog/solidjs/src/i18n.ts +62 -0
- package/dist/templates/blog/solidjs/src/main.tsx +14 -0
- package/dist/templates/blog/solidjs/src/messages.ts +71 -0
- package/dist/templates/blog/solidjs/src/model.ts +128 -0
- package/dist/templates/blog/solidjs/src/styles.css +1159 -0
- package/dist/templates/blog/solidjs/src/vite-env.d.ts +1 -0
- package/dist/templates/blog/solidjs/tsconfig.json +24 -0
- package/dist/templates/blog/solidjs/vite.config.ts +36 -0
- package/dist/templates/blog/solidjs/wrangler.jsonc +8 -0
- package/dist/templates/blog/svelte/.env.example +15 -0
- package/dist/templates/blog/svelte/ASSETS.md +1 -0
- package/dist/templates/blog/svelte/DEPLOY.md +23 -0
- package/dist/templates/blog/svelte/LICENSE +21 -0
- package/dist/templates/blog/svelte/README.md +36 -0
- package/dist/templates/blog/svelte/_gitignore +11 -0
- package/dist/templates/blog/svelte/index.html +2 -0
- package/dist/templates/blog/svelte/linguana.json +10 -0
- package/dist/templates/blog/svelte/package.json +32 -0
- package/dist/templates/blog/svelte/public/assets/scene-1.svg +1 -0
- package/dist/templates/blog/svelte/public/assets/scene-2.svg +1 -0
- package/dist/templates/blog/svelte/public/assets/scene-3.svg +1 -0
- package/dist/templates/blog/svelte/public/assets/scene-4.svg +1 -0
- package/dist/templates/blog/svelte/public/assets/scene-5.svg +1 -0
- package/dist/templates/blog/svelte/public/assets/scene-6.svg +1 -0
- package/dist/templates/blog/svelte/src/App.svelte +196 -0
- package/dist/templates/blog/svelte/src/Copy.svelte +60 -0
- package/dist/templates/blog/svelte/src/Root.svelte +11 -0
- package/dist/templates/blog/svelte/src/demo-messages.ts +221 -0
- package/dist/templates/blog/svelte/src/i18n.ts +62 -0
- package/dist/templates/blog/svelte/src/main.ts +5 -0
- package/dist/templates/blog/svelte/src/messages.ts +71 -0
- package/dist/templates/blog/svelte/src/model.ts +128 -0
- package/dist/templates/blog/svelte/src/styles.css +1159 -0
- package/dist/templates/blog/svelte/src/vite-env.d.ts +1 -0
- package/dist/templates/blog/svelte/svelte.config.js +2 -0
- package/dist/templates/blog/svelte/tsconfig.json +23 -0
- package/dist/templates/blog/svelte/vite.config.ts +36 -0
- package/dist/templates/blog/svelte/wrangler.jsonc +8 -0
- package/dist/templates/blog/tanstack-start/.env.example +15 -0
- package/dist/templates/blog/tanstack-start/ASSETS.md +1 -0
- package/dist/templates/blog/tanstack-start/DEPLOY.md +23 -0
- package/dist/templates/blog/tanstack-start/LICENSE +21 -0
- package/dist/templates/blog/tanstack-start/README.md +36 -0
- package/dist/templates/blog/tanstack-start/_gitignore +11 -0
- package/dist/templates/blog/tanstack-start/linguana.json +10 -0
- package/dist/templates/blog/tanstack-start/nitro.config.ts +2 -0
- package/dist/templates/blog/tanstack-start/package.json +42 -0
- package/dist/templates/blog/tanstack-start/public/assets/scene-1.svg +1 -0
- package/dist/templates/blog/tanstack-start/public/assets/scene-2.svg +1 -0
- package/dist/templates/blog/tanstack-start/public/assets/scene-3.svg +1 -0
- package/dist/templates/blog/tanstack-start/public/assets/scene-4.svg +1 -0
- package/dist/templates/blog/tanstack-start/public/assets/scene-5.svg +1 -0
- package/dist/templates/blog/tanstack-start/public/assets/scene-6.svg +1 -0
- package/dist/templates/blog/tanstack-start/src/App.tsx +450 -0
- package/dist/templates/blog/tanstack-start/src/Copy.tsx +322 -0
- package/dist/templates/blog/tanstack-start/src/demo-messages.ts +221 -0
- package/dist/templates/blog/tanstack-start/src/i18n.ts +62 -0
- package/dist/templates/blog/tanstack-start/src/locale-server.ts +54 -0
- package/dist/templates/blog/tanstack-start/src/messages.ts +71 -0
- package/dist/templates/blog/tanstack-start/src/model.ts +128 -0
- package/dist/templates/blog/tanstack-start/src/router.tsx +10 -0
- package/dist/templates/blog/tanstack-start/src/routes/$.tsx +7 -0
- package/dist/templates/blog/tanstack-start/src/routes/__root.tsx +50 -0
- package/dist/templates/blog/tanstack-start/src/routes/index.tsx +5 -0
- package/dist/templates/blog/tanstack-start/src/styles.css +1159 -0
- package/dist/templates/blog/tanstack-start/src/vite-env.d.ts +1 -0
- package/dist/templates/blog/tanstack-start/tsconfig.json +23 -0
- package/dist/templates/blog/tanstack-start/vite.config.ts +50 -0
- package/dist/templates/blog/tanstack-start/wrangler.jsonc +12 -0
- package/dist/templates/blog/vue/.env.example +15 -0
- package/dist/templates/blog/vue/ASSETS.md +1 -0
- package/dist/templates/blog/vue/DEPLOY.md +23 -0
- package/dist/templates/blog/vue/LICENSE +21 -0
- package/dist/templates/blog/vue/README.md +36 -0
- package/dist/templates/blog/vue/_gitignore +11 -0
- package/dist/templates/blog/vue/index.html +2 -0
- package/dist/templates/blog/vue/linguana.json +10 -0
- package/dist/templates/blog/vue/package.json +34 -0
- package/dist/templates/blog/vue/public/assets/scene-1.svg +1 -0
- package/dist/templates/blog/vue/public/assets/scene-2.svg +1 -0
- package/dist/templates/blog/vue/public/assets/scene-3.svg +1 -0
- package/dist/templates/blog/vue/public/assets/scene-4.svg +1 -0
- package/dist/templates/blog/vue/public/assets/scene-5.svg +1 -0
- package/dist/templates/blog/vue/public/assets/scene-6.svg +1 -0
- package/dist/templates/blog/vue/src/App.vue +188 -0
- package/dist/templates/blog/vue/src/Copy.vue +59 -0
- package/dist/templates/blog/vue/src/demo-messages.ts +221 -0
- package/dist/templates/blog/vue/src/i18n.ts +62 -0
- package/dist/templates/blog/vue/src/main.ts +7 -0
- package/dist/templates/blog/vue/src/messages.ts +71 -0
- package/dist/templates/blog/vue/src/model.ts +128 -0
- package/dist/templates/blog/vue/src/styles.css +1159 -0
- package/dist/templates/blog/vue/src/vite-env.d.ts +1 -0
- package/dist/templates/blog/vue/tsconfig.json +23 -0
- package/dist/templates/blog/vue/vite.config.ts +36 -0
- package/dist/templates/blog/vue/wrangler.jsonc +8 -0
- package/dist/templates/saas/react/.env.example +15 -0
- package/dist/templates/saas/react/ASSETS.md +1 -0
- package/dist/templates/saas/react/DEPLOY.md +23 -0
- package/dist/templates/saas/react/LICENSE +21 -0
- package/dist/templates/saas/react/README.md +36 -0
- package/dist/templates/saas/react/_gitignore +11 -0
- package/dist/templates/saas/react/index.html +2 -0
- package/dist/templates/saas/react/linguana.json +10 -0
- package/dist/templates/saas/react/package.json +34 -0
- package/dist/templates/saas/react/src/App.tsx +631 -0
- package/dist/templates/saas/react/src/Copy.tsx +380 -0
- package/dist/templates/saas/react/src/demo-messages.ts +228 -0
- package/dist/templates/saas/react/src/i18n.ts +62 -0
- package/dist/templates/saas/react/src/main.tsx +11 -0
- package/dist/templates/saas/react/src/messages.ts +77 -0
- package/dist/templates/saas/react/src/model.ts +73 -0
- package/dist/templates/saas/react/src/styles.css +1159 -0
- package/dist/templates/saas/react/src/vite-env.d.ts +1 -0
- package/dist/templates/saas/react/tsconfig.json +23 -0
- package/dist/templates/saas/react/vite.config.ts +36 -0
- package/dist/templates/saas/react/wrangler.jsonc +8 -0
- package/dist/templates/saas/solidjs/.env.example +15 -0
- package/dist/templates/saas/solidjs/ASSETS.md +1 -0
- package/dist/templates/saas/solidjs/DEPLOY.md +23 -0
- package/dist/templates/saas/solidjs/LICENSE +21 -0
- package/dist/templates/saas/solidjs/README.md +36 -0
- package/dist/templates/saas/solidjs/_gitignore +11 -0
- package/dist/templates/saas/solidjs/index.html +2 -0
- package/dist/templates/saas/solidjs/linguana.json +10 -0
- package/dist/templates/saas/solidjs/package.json +31 -0
- package/dist/templates/saas/solidjs/src/App.tsx +629 -0
- package/dist/templates/saas/solidjs/src/Copy.tsx +380 -0
- package/dist/templates/saas/solidjs/src/demo-messages.ts +228 -0
- package/dist/templates/saas/solidjs/src/i18n.ts +62 -0
- package/dist/templates/saas/solidjs/src/main.tsx +14 -0
- package/dist/templates/saas/solidjs/src/messages.ts +77 -0
- package/dist/templates/saas/solidjs/src/model.ts +73 -0
- package/dist/templates/saas/solidjs/src/styles.css +1159 -0
- package/dist/templates/saas/solidjs/src/vite-env.d.ts +1 -0
- package/dist/templates/saas/solidjs/tsconfig.json +24 -0
- package/dist/templates/saas/solidjs/vite.config.ts +36 -0
- package/dist/templates/saas/solidjs/wrangler.jsonc +8 -0
- package/dist/templates/saas/svelte/.env.example +15 -0
- package/dist/templates/saas/svelte/ASSETS.md +1 -0
- package/dist/templates/saas/svelte/DEPLOY.md +23 -0
- package/dist/templates/saas/svelte/LICENSE +21 -0
- package/dist/templates/saas/svelte/README.md +36 -0
- package/dist/templates/saas/svelte/_gitignore +11 -0
- package/dist/templates/saas/svelte/index.html +2 -0
- package/dist/templates/saas/svelte/linguana.json +10 -0
- package/dist/templates/saas/svelte/package.json +32 -0
- package/dist/templates/saas/svelte/src/App.svelte +252 -0
- package/dist/templates/saas/svelte/src/Copy.svelte +74 -0
- package/dist/templates/saas/svelte/src/Root.svelte +11 -0
- package/dist/templates/saas/svelte/src/demo-messages.ts +228 -0
- package/dist/templates/saas/svelte/src/i18n.ts +62 -0
- package/dist/templates/saas/svelte/src/main.ts +5 -0
- package/dist/templates/saas/svelte/src/messages.ts +77 -0
- package/dist/templates/saas/svelte/src/model.ts +73 -0
- package/dist/templates/saas/svelte/src/styles.css +1159 -0
- package/dist/templates/saas/svelte/src/vite-env.d.ts +1 -0
- package/dist/templates/saas/svelte/svelte.config.js +2 -0
- package/dist/templates/saas/svelte/tsconfig.json +23 -0
- package/dist/templates/saas/svelte/vite.config.ts +36 -0
- package/dist/templates/saas/svelte/wrangler.jsonc +8 -0
- package/dist/templates/saas/tanstack-start/.env.example +15 -0
- package/dist/templates/saas/tanstack-start/ASSETS.md +1 -0
- package/dist/templates/saas/tanstack-start/DEPLOY.md +23 -0
- package/dist/templates/saas/tanstack-start/LICENSE +21 -0
- package/dist/templates/saas/tanstack-start/README.md +36 -0
- package/dist/templates/saas/tanstack-start/_gitignore +11 -0
- package/dist/templates/saas/tanstack-start/linguana.json +10 -0
- package/dist/templates/saas/tanstack-start/nitro.config.ts +2 -0
- package/dist/templates/saas/tanstack-start/package.json +42 -0
- package/dist/templates/saas/tanstack-start/src/App.tsx +616 -0
- package/dist/templates/saas/tanstack-start/src/Copy.tsx +380 -0
- package/dist/templates/saas/tanstack-start/src/demo-messages.ts +228 -0
- package/dist/templates/saas/tanstack-start/src/i18n.ts +62 -0
- package/dist/templates/saas/tanstack-start/src/locale-server.ts +54 -0
- package/dist/templates/saas/tanstack-start/src/messages.ts +77 -0
- package/dist/templates/saas/tanstack-start/src/model.ts +73 -0
- package/dist/templates/saas/tanstack-start/src/router.tsx +10 -0
- package/dist/templates/saas/tanstack-start/src/routes/$.tsx +7 -0
- package/dist/templates/saas/tanstack-start/src/routes/__root.tsx +50 -0
- package/dist/templates/saas/tanstack-start/src/routes/index.tsx +5 -0
- package/dist/templates/saas/tanstack-start/src/styles.css +1159 -0
- package/dist/templates/saas/tanstack-start/src/vite-env.d.ts +1 -0
- package/dist/templates/saas/tanstack-start/tsconfig.json +23 -0
- package/dist/templates/saas/tanstack-start/vite.config.ts +50 -0
- package/dist/templates/saas/tanstack-start/wrangler.jsonc +12 -0
- package/dist/templates/saas/vue/.env.example +15 -0
- package/dist/templates/saas/vue/ASSETS.md +1 -0
- package/dist/templates/saas/vue/DEPLOY.md +23 -0
- package/dist/templates/saas/vue/LICENSE +21 -0
- package/dist/templates/saas/vue/README.md +36 -0
- package/dist/templates/saas/vue/_gitignore +11 -0
- package/dist/templates/saas/vue/index.html +2 -0
- package/dist/templates/saas/vue/linguana.json +10 -0
- package/dist/templates/saas/vue/package.json +34 -0
- package/dist/templates/saas/vue/src/App.vue +244 -0
- package/dist/templates/saas/vue/src/Copy.vue +73 -0
- package/dist/templates/saas/vue/src/demo-messages.ts +228 -0
- package/dist/templates/saas/vue/src/i18n.ts +62 -0
- package/dist/templates/saas/vue/src/main.ts +7 -0
- package/dist/templates/saas/vue/src/messages.ts +77 -0
- package/dist/templates/saas/vue/src/model.ts +73 -0
- package/dist/templates/saas/vue/src/styles.css +1159 -0
- package/dist/templates/saas/vue/src/vite-env.d.ts +1 -0
- package/dist/templates/saas/vue/tsconfig.json +23 -0
- package/dist/templates/saas/vue/vite.config.ts +36 -0
- package/dist/templates/saas/vue/wrangler.jsonc +8 -0
- package/dist/templates/storefront/react/.env.example +15 -0
- package/dist/templates/storefront/react/ASSETS.md +1 -0
- package/dist/templates/storefront/react/DEPLOY.md +23 -0
- package/dist/templates/storefront/react/LICENSE +21 -0
- package/dist/templates/storefront/react/README.md +36 -0
- package/dist/templates/storefront/react/_gitignore +11 -0
- package/dist/templates/storefront/react/index.html +2 -0
- package/dist/templates/storefront/react/linguana.json +10 -0
- package/dist/templates/storefront/react/package.json +34 -0
- package/dist/templates/storefront/react/public/assets/collection.svg +1 -0
- package/dist/templates/storefront/react/public/assets/product-1.svg +1 -0
- package/dist/templates/storefront/react/public/assets/product-2.svg +1 -0
- package/dist/templates/storefront/react/public/assets/product-3.svg +1 -0
- package/dist/templates/storefront/react/public/assets/product-4.svg +1 -0
- package/dist/templates/storefront/react/public/assets/product-5.svg +1 -0
- package/dist/templates/storefront/react/public/assets/product-6.svg +1 -0
- package/dist/templates/storefront/react/public/assets/product-7.svg +1 -0
- package/dist/templates/storefront/react/public/assets/product-8.svg +1 -0
- package/dist/templates/storefront/react/src/App.tsx +616 -0
- package/dist/templates/storefront/react/src/Copy.tsx +304 -0
- package/dist/templates/storefront/react/src/demo-messages.ts +205 -0
- package/dist/templates/storefront/react/src/i18n.ts +64 -0
- package/dist/templates/storefront/react/src/main.tsx +11 -0
- package/dist/templates/storefront/react/src/messages.ts +71 -0
- package/dist/templates/storefront/react/src/model.ts +146 -0
- package/dist/templates/storefront/react/src/styles.css +1159 -0
- package/dist/templates/storefront/react/src/vite-env.d.ts +1 -0
- package/dist/templates/storefront/react/tsconfig.json +23 -0
- package/dist/templates/storefront/react/vite.config.ts +36 -0
- package/dist/templates/storefront/react/wrangler.jsonc +8 -0
- package/dist/templates/storefront/solidjs/.env.example +15 -0
- package/dist/templates/storefront/solidjs/ASSETS.md +1 -0
- package/dist/templates/storefront/solidjs/DEPLOY.md +23 -0
- package/dist/templates/storefront/solidjs/LICENSE +21 -0
- package/dist/templates/storefront/solidjs/README.md +36 -0
- package/dist/templates/storefront/solidjs/_gitignore +11 -0
- package/dist/templates/storefront/solidjs/index.html +2 -0
- package/dist/templates/storefront/solidjs/linguana.json +10 -0
- package/dist/templates/storefront/solidjs/package.json +31 -0
- package/dist/templates/storefront/solidjs/public/assets/collection.svg +1 -0
- package/dist/templates/storefront/solidjs/public/assets/product-1.svg +1 -0
- package/dist/templates/storefront/solidjs/public/assets/product-2.svg +1 -0
- package/dist/templates/storefront/solidjs/public/assets/product-3.svg +1 -0
- package/dist/templates/storefront/solidjs/public/assets/product-4.svg +1 -0
- package/dist/templates/storefront/solidjs/public/assets/product-5.svg +1 -0
- package/dist/templates/storefront/solidjs/public/assets/product-6.svg +1 -0
- package/dist/templates/storefront/solidjs/public/assets/product-7.svg +1 -0
- package/dist/templates/storefront/solidjs/public/assets/product-8.svg +1 -0
- package/dist/templates/storefront/solidjs/src/App.tsx +612 -0
- package/dist/templates/storefront/solidjs/src/Copy.tsx +304 -0
- package/dist/templates/storefront/solidjs/src/demo-messages.ts +205 -0
- package/dist/templates/storefront/solidjs/src/i18n.ts +64 -0
- package/dist/templates/storefront/solidjs/src/main.tsx +14 -0
- package/dist/templates/storefront/solidjs/src/messages.ts +71 -0
- package/dist/templates/storefront/solidjs/src/model.ts +146 -0
- package/dist/templates/storefront/solidjs/src/styles.css +1159 -0
- package/dist/templates/storefront/solidjs/src/vite-env.d.ts +1 -0
- package/dist/templates/storefront/solidjs/tsconfig.json +24 -0
- package/dist/templates/storefront/solidjs/vite.config.ts +36 -0
- package/dist/templates/storefront/solidjs/wrangler.jsonc +8 -0
- package/dist/templates/storefront/svelte/.env.example +15 -0
- package/dist/templates/storefront/svelte/ASSETS.md +1 -0
- package/dist/templates/storefront/svelte/DEPLOY.md +23 -0
- package/dist/templates/storefront/svelte/LICENSE +21 -0
- package/dist/templates/storefront/svelte/README.md +36 -0
- package/dist/templates/storefront/svelte/_gitignore +11 -0
- package/dist/templates/storefront/svelte/index.html +2 -0
- package/dist/templates/storefront/svelte/linguana.json +10 -0
- package/dist/templates/storefront/svelte/package.json +32 -0
- package/dist/templates/storefront/svelte/public/assets/collection.svg +1 -0
- package/dist/templates/storefront/svelte/public/assets/product-1.svg +1 -0
- package/dist/templates/storefront/svelte/public/assets/product-2.svg +1 -0
- package/dist/templates/storefront/svelte/public/assets/product-3.svg +1 -0
- package/dist/templates/storefront/svelte/public/assets/product-4.svg +1 -0
- package/dist/templates/storefront/svelte/public/assets/product-5.svg +1 -0
- package/dist/templates/storefront/svelte/public/assets/product-6.svg +1 -0
- package/dist/templates/storefront/svelte/public/assets/product-7.svg +1 -0
- package/dist/templates/storefront/svelte/public/assets/product-8.svg +1 -0
- package/dist/templates/storefront/svelte/src/App.svelte +218 -0
- package/dist/templates/storefront/svelte/src/Copy.svelte +66 -0
- package/dist/templates/storefront/svelte/src/Root.svelte +11 -0
- package/dist/templates/storefront/svelte/src/demo-messages.ts +205 -0
- package/dist/templates/storefront/svelte/src/i18n.ts +64 -0
- package/dist/templates/storefront/svelte/src/main.ts +5 -0
- package/dist/templates/storefront/svelte/src/messages.ts +71 -0
- package/dist/templates/storefront/svelte/src/model.ts +146 -0
- package/dist/templates/storefront/svelte/src/styles.css +1159 -0
- package/dist/templates/storefront/svelte/src/vite-env.d.ts +1 -0
- package/dist/templates/storefront/svelte/svelte.config.js +2 -0
- package/dist/templates/storefront/svelte/tsconfig.json +23 -0
- package/dist/templates/storefront/svelte/vite.config.ts +36 -0
- package/dist/templates/storefront/svelte/wrangler.jsonc +8 -0
- package/dist/templates/storefront/tanstack-start/.env.example +15 -0
- package/dist/templates/storefront/tanstack-start/ASSETS.md +1 -0
- package/dist/templates/storefront/tanstack-start/DEPLOY.md +23 -0
- package/dist/templates/storefront/tanstack-start/LICENSE +21 -0
- package/dist/templates/storefront/tanstack-start/README.md +36 -0
- package/dist/templates/storefront/tanstack-start/_gitignore +11 -0
- package/dist/templates/storefront/tanstack-start/linguana.json +10 -0
- package/dist/templates/storefront/tanstack-start/nitro.config.ts +2 -0
- package/dist/templates/storefront/tanstack-start/package.json +42 -0
- package/dist/templates/storefront/tanstack-start/public/assets/collection.svg +1 -0
- package/dist/templates/storefront/tanstack-start/public/assets/product-1.svg +1 -0
- package/dist/templates/storefront/tanstack-start/public/assets/product-2.svg +1 -0
- package/dist/templates/storefront/tanstack-start/public/assets/product-3.svg +1 -0
- package/dist/templates/storefront/tanstack-start/public/assets/product-4.svg +1 -0
- package/dist/templates/storefront/tanstack-start/public/assets/product-5.svg +1 -0
- package/dist/templates/storefront/tanstack-start/public/assets/product-6.svg +1 -0
- package/dist/templates/storefront/tanstack-start/public/assets/product-7.svg +1 -0
- package/dist/templates/storefront/tanstack-start/public/assets/product-8.svg +1 -0
- package/dist/templates/storefront/tanstack-start/src/App.tsx +601 -0
- package/dist/templates/storefront/tanstack-start/src/Copy.tsx +304 -0
- package/dist/templates/storefront/tanstack-start/src/demo-messages.ts +205 -0
- package/dist/templates/storefront/tanstack-start/src/i18n.ts +64 -0
- package/dist/templates/storefront/tanstack-start/src/locale-server.ts +54 -0
- package/dist/templates/storefront/tanstack-start/src/messages.ts +71 -0
- package/dist/templates/storefront/tanstack-start/src/model.ts +146 -0
- package/dist/templates/storefront/tanstack-start/src/router.tsx +10 -0
- package/dist/templates/storefront/tanstack-start/src/routes/$.tsx +7 -0
- package/dist/templates/storefront/tanstack-start/src/routes/__root.tsx +50 -0
- package/dist/templates/storefront/tanstack-start/src/routes/index.tsx +5 -0
- package/dist/templates/storefront/tanstack-start/src/styles.css +1159 -0
- package/dist/templates/storefront/tanstack-start/src/vite-env.d.ts +1 -0
- package/dist/templates/storefront/tanstack-start/tsconfig.json +23 -0
- package/dist/templates/storefront/tanstack-start/vite.config.ts +50 -0
- package/dist/templates/storefront/tanstack-start/wrangler.jsonc +12 -0
- package/dist/templates/storefront/vue/.env.example +15 -0
- package/dist/templates/storefront/vue/ASSETS.md +1 -0
- package/dist/templates/storefront/vue/DEPLOY.md +23 -0
- package/dist/templates/storefront/vue/LICENSE +21 -0
- package/dist/templates/storefront/vue/README.md +36 -0
- package/dist/templates/storefront/vue/_gitignore +11 -0
- package/dist/templates/storefront/vue/index.html +2 -0
- package/dist/templates/storefront/vue/linguana.json +10 -0
- package/dist/templates/storefront/vue/package.json +34 -0
- package/dist/templates/storefront/vue/public/assets/collection.svg +1 -0
- package/dist/templates/storefront/vue/public/assets/product-1.svg +1 -0
- package/dist/templates/storefront/vue/public/assets/product-2.svg +1 -0
- package/dist/templates/storefront/vue/public/assets/product-3.svg +1 -0
- package/dist/templates/storefront/vue/public/assets/product-4.svg +1 -0
- package/dist/templates/storefront/vue/public/assets/product-5.svg +1 -0
- package/dist/templates/storefront/vue/public/assets/product-6.svg +1 -0
- package/dist/templates/storefront/vue/public/assets/product-7.svg +1 -0
- package/dist/templates/storefront/vue/public/assets/product-8.svg +1 -0
- package/dist/templates/storefront/vue/src/App.vue +210 -0
- package/dist/templates/storefront/vue/src/Copy.vue +65 -0
- package/dist/templates/storefront/vue/src/demo-messages.ts +205 -0
- package/dist/templates/storefront/vue/src/i18n.ts +64 -0
- package/dist/templates/storefront/vue/src/main.ts +7 -0
- package/dist/templates/storefront/vue/src/messages.ts +71 -0
- package/dist/templates/storefront/vue/src/model.ts +146 -0
- package/dist/templates/storefront/vue/src/styles.css +1159 -0
- package/dist/templates/storefront/vue/src/vite-env.d.ts +1 -0
- package/dist/templates/storefront/vue/tsconfig.json +23 -0
- package/dist/templates/storefront/vue/vite.config.ts +36 -0
- package/dist/templates/storefront/vue/wrangler.jsonc +8 -0
- package/package.json +38 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"moduleResolution": "Bundler",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"allowImportingTsExtensions": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"types": ["vite/client", "node"],
|
|
14
|
+
"jsx": "react-jsx"
|
|
15
|
+
},
|
|
16
|
+
"include": [
|
|
17
|
+
"src/**/*.ts",
|
|
18
|
+
"src/**/*.tsx",
|
|
19
|
+
"src/**/*.vue",
|
|
20
|
+
"src/**/*.svelte",
|
|
21
|
+
"vite.config.ts"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { linguana } from "@linguanahq/vite";
|
|
3
|
+
import { react } from "@linguanahq/vite/react";
|
|
4
|
+
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
|
|
5
|
+
import native from "@vitejs/plugin-react";
|
|
6
|
+
import { nitro } from "nitro/vite";
|
|
7
|
+
import { defineConfig, loadEnv } from "vite";
|
|
8
|
+
import config from "./linguana.json" with { type: "json" };
|
|
9
|
+
export default defineConfig(({ mode }) => {
|
|
10
|
+
const env = { ...loadEnv(mode, process.cwd(), ""), ...process.env };
|
|
11
|
+
const connected = config.mode === "connected";
|
|
12
|
+
if (
|
|
13
|
+
connected &&
|
|
14
|
+
(!env.LINGUANA_PROJECT_ID ||
|
|
15
|
+
!env.VITE_LINGUANA_PUBLISHABLE_KEY ||
|
|
16
|
+
env.LINGUANA_PROJECT_ID !== env.VITE_LINGUANA_PROJECT_ID ||
|
|
17
|
+
env.LINGUANA_ENVIRONMENT !== env.VITE_LINGUANA_ENVIRONMENT ||
|
|
18
|
+
env.LINGUANA_API_URL !== env.VITE_LINGUANA_API_URL)
|
|
19
|
+
)
|
|
20
|
+
throw new Error(
|
|
21
|
+
"Linguana environment is incomplete or inconsistent. Run linguana env pull for this build mode.",
|
|
22
|
+
);
|
|
23
|
+
return {
|
|
24
|
+
resolve: {
|
|
25
|
+
alias: [
|
|
26
|
+
{
|
|
27
|
+
find: "tslib",
|
|
28
|
+
replacement: fileURLToPath(
|
|
29
|
+
import.meta.resolve("tslib/tslib.es6.mjs"),
|
|
30
|
+
),
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
plugins: [
|
|
35
|
+
linguana({
|
|
36
|
+
adapter: react(),
|
|
37
|
+
projectId: connected ? env.LINGUANA_PROJECT_ID! : "demo-blog",
|
|
38
|
+
environment: connected ? env.LINGUANA_ENVIRONMENT : "development",
|
|
39
|
+
sourceLocale: config.sourceLocale,
|
|
40
|
+
apiUrl: connected ? env.LINGUANA_API_URL : undefined,
|
|
41
|
+
token: connected ? env.LINGUANA_PROJECT_TOKEN : undefined,
|
|
42
|
+
upload: connected && env.LINGUANA_UPLOAD === "true",
|
|
43
|
+
translation: false,
|
|
44
|
+
}),
|
|
45
|
+
tanstackStart(),
|
|
46
|
+
nitro(),
|
|
47
|
+
native(),
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Demo mode works without credentials. Connect with npx @linguanahq/cli link.
|
|
2
|
+
# Copying this file alone does not enable connected mode; use linguana.json.
|
|
3
|
+
# Build/server only. NEVER prefix the project token with VITE_.
|
|
4
|
+
LINGUANA_PROJECT_ID=
|
|
5
|
+
LINGUANA_ENVIRONMENT=development
|
|
6
|
+
LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
|
|
7
|
+
LINGUANA_PROJECT_TOKEN=
|
|
8
|
+
LINGUANA_UPLOAD=false
|
|
9
|
+
# Paid translation is disabled; this template does not enable it automatically.
|
|
10
|
+
LINGUANA_TRANSLATE=false
|
|
11
|
+
# Browser-safe values. A publishable key reads published catalogs only.
|
|
12
|
+
VITE_LINGUANA_PROJECT_ID=
|
|
13
|
+
VITE_LINGUANA_ENVIRONMENT=development
|
|
14
|
+
VITE_LINGUANA_API_URL=https://linguana-api.mohammedibrahim.dev
|
|
15
|
+
VITE_LINGUANA_PUBLISHABLE_KEY=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
All illustrations in public/assets were drawn for these templates and are covered by LICENSE (MIT). Sample writing and translations are also MIT. No remote images, tracking pixels, or font services are used. Product images and prices describe fictional demonstration goods.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Deploy Elsewhere
|
|
2
|
+
|
|
3
|
+
Demo mode needs no Linguana account. Hosting authentication is separate from the Linguana CLI.
|
|
4
|
+
|
|
5
|
+
## Cloudflare Workers
|
|
6
|
+
|
|
7
|
+
Install dependencies, choose a unique Worker name in wrangler.jsonc, then:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npx wrangler login
|
|
11
|
+
npm run build
|
|
12
|
+
npx wrangler deploy
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Wrangler serves dist as static assets with single-page navigation fallback. Deep article/product links continue to work.
|
|
16
|
+
|
|
17
|
+
## Any static host
|
|
18
|
+
|
|
19
|
+
Run `npm run build` and publish dist/. Configure unknown paths to serve /index.html with status 200 (SPA fallback). A static preview can be started with `npm run preview`. Do not publish the project root.
|
|
20
|
+
|
|
21
|
+
## Connected deployments
|
|
22
|
+
|
|
23
|
+
Pull the intended environment with `linguana env pull --environment production`. Configure the variables from .env.example in the build host, including the matching public project/environment values. Build tokens are secrets used by the compiler only. Never upload .env files or the CLI account session. LINGUANA_TRANSLATE remains false. Catalog publication is an explicit dashboard action.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Linguana contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Elsewhere
|
|
2
|
+
|
|
3
|
+
A journal for the places worth taking your time in. Articles, search, and thoughtful reading layouts.
|
|
4
|
+
|
|
5
|
+
A standalone vue app, generated from Linguana templates v0.1.0. Requires Node 22.12+ (or Bun).
|
|
6
|
+
|
|
7
|
+
## Run
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install
|
|
11
|
+
npm run dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
You can also use pnpm, Yarn, or Bun. English, French, Spanish, and Arabic catalogs are bundled in demo mode. No Linguana API requests are made. The language cookie persists between visits. Arabic switches the document to RTL.
|
|
15
|
+
|
|
16
|
+
## Connect your own project
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npx @linguanahq/cli login
|
|
20
|
+
npx @linguanahq/cli link
|
|
21
|
+
npx @linguanahq/cli doctor
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Linking writes nonsecret `linguana.json` and ignored `.env.local`. The account session stays outside this project. Only the public project ID, environment, API URL, and publishable key reach the browser. Build tokens never belong in `VITE_*` variables.
|
|
25
|
+
|
|
26
|
+
Connected mode uses your published project catalogs and English source fallback. It does not load demo translations. Builds can upload the source manifest but do not start paid translations or publish catalogs. Review and publish translations in your dashboard. Existing project languages remain unchanged unless you pass `--locales`.
|
|
27
|
+
|
|
28
|
+
To target another environment, use `linguana env pull --environment staging`, then `npm run build -- --mode staging`. Production uses `.env.production.local` and Vite's default production build mode. Configure matching private and public values on your build host; see .env.example.
|
|
29
|
+
|
|
30
|
+
## Customize
|
|
31
|
+
|
|
32
|
+
Edit native components in src/App.vue, literal messages in src/Copy.vue, source fallbacks in src/messages.ts, and bundled demo catalogs in src/demo-messages.ts. Keep explicit message IDs stable. Each Copy branch is an extractable literal message; structured items in src/model.ts hold identifiers, prices, dates, and media only. Build output includes .linguana/manifest.json for review.
|
|
33
|
+
|
|
34
|
+
Six articles include detail routes, category and search filters, localized dates, and a not-found view.
|
|
35
|
+
|
|
36
|
+
Run `npm run check-types` and `npm run build` before deploying. Deployment instructions are in DEPLOY.md. Source and illustrations are MIT; see LICENSE and ASSETS.md.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content="A journal for the places worth taking your time in. Articles, search, and thoughtful reading layouts."><meta name="theme-color" content="#244d64"><title>Elsewhere</title></head><body><div id="app"></div><script type="module" src="/src/main.ts"></script></body></html>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "blog-vue",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22.12.0"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "vite --host 127.0.0.1",
|
|
12
|
+
"build": "vite build",
|
|
13
|
+
"preview": "vite preview",
|
|
14
|
+
"check-types": "vue-tsc --noEmit",
|
|
15
|
+
"deploy": "npm run build && wrangler deploy"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@linguanahq/catalog": "0.1.1",
|
|
19
|
+
"@linguanahq/core": "0.1.1",
|
|
20
|
+
"@linguanahq/vue": "0.1.1",
|
|
21
|
+
"vue": "^3.5.24"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@linguanahq/vite": "0.1.1",
|
|
25
|
+
"typescript": "^6.0.0",
|
|
26
|
+
"vite": "^8.1.3",
|
|
27
|
+
"@types/node": "^24.0.0",
|
|
28
|
+
"wrangler": "^4.127.0",
|
|
29
|
+
"@vitejs/plugin-vue": "^6.0.2",
|
|
30
|
+
"@vue/compiler-dom": "^3.5.24",
|
|
31
|
+
"@vue/compiler-sfc": "^3.5.24",
|
|
32
|
+
"vue-tsc": "^3.1.0"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" viewBox="0 0 800 600"><title>Original Linguana template illustration</title><rect width="800" height="600" fill="#dbe6e9"/><circle cx="640" cy="115" r="53" fill="#f3e6c9"/><path d="M0 330L170 160 310 290 500 210 800 350V600H0Z" fill="#748e9a"/><g stroke="#f4ead8" stroke-width="5"><path d="M55 260H255V540H55Z" fill="#d18d73"/><path d="M300 190H500V540H300Z" fill="#e9d3ad"/><path d="M545 290H765V540H545Z" fill="#92a4a1"/></g><g fill="#456071"><path d="M80 250L155 205 255 250ZM285 183L397 135 515 183ZM531 283L657 239 779 283Z"/><path d="M91 296h36v58H91zm85 0h36v58h-36zm-85 100h36v58H91zm85 0h36v58h-36zm165-170h38v63h-38zm85 0h38v63h-38zm-85 100h38v63h-38zm85 0h38v63h-38zm162 0h38v64h-38zm92 0h38v64h-38z"/></g><path d="M356 540V448q42-50 84 0v92M118 540v-53q40-50 80 0v53M610 540v-75h70v75" fill="#bc705d"/><path d="M0 545h800v55H0Z" fill="#cecbbb"/><path d="M0 580h800" stroke="#adb9b7" stroke-width="3"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" viewBox="0 0 800 600"><title>Original Linguana template illustration</title><rect width="800" height="600" fill="#dce5db"/><circle cx="640" cy="115" r="53" fill="#f3e6c9"/><path d="M0 300q130-80 300 0t500-10v150H0Z" fill="#9aac9f"/><path d="M0 370 Q200 330 400 380 T800 360V600H0Z" fill="#738d7a"/><path d="M60 430h160m80 35h220m40-40h170M30 530h240m200 15h180" stroke="#dbe7e4" stroke-width="3" opacity=".7"/><g fill="#3f685e"><path d="M75 50l60 280H15ZM195 5l80 340H115ZM700 30l75 330H625ZM770 70l60 300H710Z"/></g><path d="M265 340h270v170H265Z" fill="#b99b7e"/><path d="M240 342l160-125 160 125Z" fill="#526c68"/><path d="M308 380h65v70h-65Zm120 0h65v70h-65Z" fill="#e9d3a2"/><path d="M390 430h30v80h-30Z" fill="#4e6866"/><path d="M0 510q240-80 400 20t400-10v80H0Z" fill="#899e80"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" viewBox="0 0 800 600"><title>Original Linguana template illustration</title><rect width="800" height="600" fill="#d4e5e7"/><circle cx="640" cy="115" r="53" fill="#f3e6c9"/><path d="M0 370 Q200 330 400 380 T800 360V600H0Z" fill="#628697"/><path d="M60 430h160m80 35h220m40-40h170M30 530h240m200 15h180" stroke="#dbe7e4" stroke-width="3" opacity=".7"/><path d="M0 160q130 120 300 155l170 190-280-35L0 600Z" fill="#d9c39e"/><path d="M0 300l275 43 120 72-285 19L0 530" fill="#dec6a0"/><path d="M630 310q120-60 170-55v90Z" fill="#8da39a"/><path d="M30 510q180-80 330-56" fill="none" stroke="#efe0bf" stroke-width="14"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" viewBox="0 0 800 600"><title>Original Linguana template illustration</title><rect width="800" height="600" fill="#dfe6ed"/><circle cx="640" cy="115" r="53" fill="#f3e6c9"/><path d="M0 460L195 110 350 300 470 100 800 470V600H0Z" fill="#7b8fa1"/><path d="M195 110l-45 85 42-20 28 22 13-25zM470 100l-58 110 57-20 20 32 28-40z" fill="#f4f4ec"/><path d="M0 480q160-120 370 10t430-20v130H0Z" fill="#a8b39a"/><path d="M350 600q130-100 65-160" fill="none" stroke="#d9ceb6" stroke-width="18"/><path d="M70 450v80h110v-80Z" fill="#977666"/><path d="M50 450l76-50 78 50Z" fill="#405f65"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" viewBox="0 0 800 600"><title>Original Linguana template illustration</title><rect width="800" height="600" fill="#e0e9e6"/><circle cx="640" cy="115" r="53" fill="#f3e6c9"/><path d="M0 330L170 160 310 290 500 210 800 350V600H0Z" fill="#769496"/><path d="M0 370 Q200 330 400 380 T800 360V600H0Z" fill="#769496"/><path d="M60 430h160m80 35h220m40-40h170M30 530h240m200 15h180" stroke="#dbe7e4" stroke-width="3" opacity=".7"/><g stroke="#f4ead8" stroke-width="5"><path d="M55 260H255V540H55Z" fill="#bc8871"/><path d="M300 190H500V540H300Z" fill="#e9d3ad"/><path d="M545 290H765V540H545Z" fill="#92a4a1"/></g><g fill="#456071"><path d="M80 250L155 205 255 250ZM285 183L397 135 515 183ZM531 283L657 239 779 283Z"/><path d="M91 296h36v58H91zm85 0h36v58h-36zm-85 100h36v58H91zm85 0h36v58h-36zm165-170h38v63h-38zm85 0h38v63h-38zm-85 100h38v63h-38zm85 0h38v63h-38zm162 0h38v64h-38zm92 0h38v64h-38z"/></g><path d="M356 540V448q42-50 84 0v92M118 540v-53q40-50 80 0v53M610 540v-75h70v75" fill="#bc705d"/><path d="M0 545h800v55H0Z" fill="#cecbbb"/><path d="M0 580h800" stroke="#adb9b7" stroke-width="3"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" viewBox="0 0 800 600"><title>Original Linguana template illustration</title><rect width="800" height="600" fill="#e0e7e6"/><circle cx="640" cy="115" r="53" fill="#f3e6c9"/><path d="M0 300q130-80 300 0t500-10v150H0Z" fill="#9aac9f"/><path d="M0 370 Q200 330 400 380 T800 360V600H0Z" fill="#76948a"/><path d="M60 430h160m80 35h220m40-40h170M30 530h240m200 15h180" stroke="#dbe7e4" stroke-width="3" opacity=".7"/><g fill="#3f685e"><path d="M75 50l60 280H15ZM195 5l80 340H115ZM700 30l75 330H625ZM770 70l60 300H710Z"/></g><path d="M265 340h270v170H265Z" fill="#a78f77"/><path d="M240 342l160-125 160 125Z" fill="#526c68"/><path d="M308 380h65v70h-65Zm120 0h65v70h-65Z" fill="#e9d3a2"/><path d="M390 430h30v80h-30Z" fill="#4e6866"/><path d="M0 510q240-80 400 20t400-10v80H0Z" fill="#899e80"/></svg>
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useTranslation } from "@linguanahq/vue";
|
|
3
|
+
import { onMounted, onUnmounted, reactive, watchEffect } from "vue";
|
|
4
|
+
import Copy from "./Copy.vue";
|
|
5
|
+
import { demoLocales } from "./i18n";
|
|
6
|
+
import { messages } from "./messages";
|
|
7
|
+
import {
|
|
8
|
+
initialState,
|
|
9
|
+
items,
|
|
10
|
+
quantity,
|
|
11
|
+
readCart,
|
|
12
|
+
type State,
|
|
13
|
+
saveCart,
|
|
14
|
+
} from "./model";
|
|
15
|
+
|
|
16
|
+
const runtime = useTranslation();
|
|
17
|
+
const locale = () => runtime.locale.value;
|
|
18
|
+
const translate = runtime.translate;
|
|
19
|
+
const locales = () =>
|
|
20
|
+
runtime.availableLocales.value.length
|
|
21
|
+
? runtime.availableLocales.value
|
|
22
|
+
: demoLocales.filter((item) => item.code === "en");
|
|
23
|
+
const changeLocale = (value: string) => void runtime.setLocale(value);
|
|
24
|
+
const state = reactive(initialState());
|
|
25
|
+
const set = <K extends keyof State>(key: K, value: State[K]) => {
|
|
26
|
+
state[key] = value;
|
|
27
|
+
};
|
|
28
|
+
const pop = () => set("path", window.location.pathname);
|
|
29
|
+
onMounted(() => {
|
|
30
|
+
set("cart", readCart());
|
|
31
|
+
window.addEventListener("popstate", pop);
|
|
32
|
+
});
|
|
33
|
+
onUnmounted(() => window.removeEventListener("popstate", pop));
|
|
34
|
+
watchEffect(() => {
|
|
35
|
+
document.documentElement.lang = locale();
|
|
36
|
+
document.documentElement.dir = locale().startsWith("ar") ? "rtl" : "ltr";
|
|
37
|
+
});
|
|
38
|
+
const msg = (id: string, values?: Record<string, string | number>) =>
|
|
39
|
+
String(translate(id, messages[id] ?? id, values));
|
|
40
|
+
const value = (event: Event | { currentTarget: EventTarget | null }) =>
|
|
41
|
+
(event.currentTarget as HTMLInputElement).value;
|
|
42
|
+
const money = (amount: number) =>
|
|
43
|
+
new Intl.NumberFormat(locale(), {
|
|
44
|
+
style: "currency",
|
|
45
|
+
currency: "USD",
|
|
46
|
+
maximumFractionDigits: 2,
|
|
47
|
+
}).format(amount);
|
|
48
|
+
const date = (input: string) =>
|
|
49
|
+
new Intl.DateTimeFormat(locale(), {
|
|
50
|
+
dateStyle: "medium",
|
|
51
|
+
timeZone: "UTC",
|
|
52
|
+
}).format(new Date(input));
|
|
53
|
+
const visible = () =>
|
|
54
|
+
items
|
|
55
|
+
.filter(
|
|
56
|
+
(item) =>
|
|
57
|
+
(state.category === "all" || item.category === state.category) &&
|
|
58
|
+
`${msg(`${item.id}Title`)} ${msg(`${item.id}Summary`)}`
|
|
59
|
+
.toLocaleLowerCase(locale())
|
|
60
|
+
.includes(state.query.toLocaleLowerCase(locale()).trim()),
|
|
61
|
+
)
|
|
62
|
+
.sort((a, b) =>
|
|
63
|
+
state.sort === "low"
|
|
64
|
+
? a.price - b.price
|
|
65
|
+
: state.sort === "high"
|
|
66
|
+
? b.price - a.price
|
|
67
|
+
: 0,
|
|
68
|
+
);
|
|
69
|
+
const detailHref = (id: string) =>
|
|
70
|
+
`/articles/${items.find((item) => item.id === id)!.slug}`;
|
|
71
|
+
const detail = () => items.find((item) => detailHref(item.id) === state.path);
|
|
72
|
+
const notFound = () => state.path !== "/" && detail() === undefined;
|
|
73
|
+
const clearFilters = () => {
|
|
74
|
+
set("query", "");
|
|
75
|
+
set("category", "all");
|
|
76
|
+
};
|
|
77
|
+
const count = () =>
|
|
78
|
+
Object.values(state.cart).reduce((total, count) => total + count, 0);
|
|
79
|
+
const cartItems = () => items.filter((item) => (state.cart[item.id] ?? 0) > 0);
|
|
80
|
+
const total = () =>
|
|
81
|
+
cartItems().reduce(
|
|
82
|
+
(total, item) => total + item.price * state.cart[item.id]!,
|
|
83
|
+
0,
|
|
84
|
+
);
|
|
85
|
+
const updateCart = (id: string, count: number) => {
|
|
86
|
+
const cart = { ...state.cart };
|
|
87
|
+
if (count <= 0) delete cart[id];
|
|
88
|
+
else cart[id] = quantity(count);
|
|
89
|
+
set("cart", cart);
|
|
90
|
+
saveCart(cart);
|
|
91
|
+
};
|
|
92
|
+
const add = (id: string, count: number) => {
|
|
93
|
+
updateCart(id, (state.cart[id] ?? 0) + count);
|
|
94
|
+
set("added", true);
|
|
95
|
+
set("checkout", false);
|
|
96
|
+
};
|
|
97
|
+
const checkout = () => {
|
|
98
|
+
set("cart", {});
|
|
99
|
+
saveCart({});
|
|
100
|
+
set("checkout", true);
|
|
101
|
+
set("added", false);
|
|
102
|
+
};
|
|
103
|
+
const submit = (event: { preventDefault(): void }) => {
|
|
104
|
+
event.preventDefault();
|
|
105
|
+
const valid = Boolean(
|
|
106
|
+
state.name.trim() && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(state.email),
|
|
107
|
+
);
|
|
108
|
+
set("error", !valid);
|
|
109
|
+
set("sent", valid);
|
|
110
|
+
};
|
|
111
|
+
const navigate = (event: {
|
|
112
|
+
currentTarget: EventTarget | null;
|
|
113
|
+
preventDefault(): void;
|
|
114
|
+
metaKey: boolean;
|
|
115
|
+
ctrlKey: boolean;
|
|
116
|
+
shiftKey: boolean;
|
|
117
|
+
altKey: boolean;
|
|
118
|
+
button: number;
|
|
119
|
+
}) => {
|
|
120
|
+
if (
|
|
121
|
+
event.metaKey ||
|
|
122
|
+
event.ctrlKey ||
|
|
123
|
+
event.shiftKey ||
|
|
124
|
+
event.altKey ||
|
|
125
|
+
event.button !== 0
|
|
126
|
+
)
|
|
127
|
+
return;
|
|
128
|
+
const target = new URL((event.currentTarget as HTMLAnchorElement).href);
|
|
129
|
+
if (target.origin !== window.location.origin) return;
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
window.history.pushState({}, "", target.pathname);
|
|
132
|
+
set("path", target.pathname);
|
|
133
|
+
set("quantity", 1);
|
|
134
|
+
set("added", false);
|
|
135
|
+
window.scrollTo(0, 0);
|
|
136
|
+
};
|
|
137
|
+
</script>
|
|
138
|
+
<template>
|
|
139
|
+
<div class="site blog"><a href="#main" class="skip-link"><Copy name="skip"></Copy></a>
|
|
140
|
+
<header class="site-header"><a href="/" class="brand" @click="navigate($event)" :aria-label="'Elsewhere — ' + msg('home')"><span class="brand-mark" aria-hidden="true">✳</span>
|
|
141
|
+
Elsewhere</a>
|
|
142
|
+
<nav :aria-label="msg('home')"><a href="/" @click="navigate($event)"><Copy name="latest"></Copy></a>
|
|
143
|
+
<label class="locale-picker"><span class="sr-only"><Copy name="language"></Copy></span>
|
|
144
|
+
<select :value="locale()" :aria-label="msg('language')" @change="changeLocale(value($event))"><template v-for="language in locales()" :key="language.code"><option :value="language.code">{{ language.nativeName }}</option></template></select></label></nav></header>
|
|
145
|
+
<main id="main"><template v-if="state.path === '/'"><section class="hero blog-hero"><div class="hero-copy"><p class="eyebrow"><Copy name="eyebrow"></Copy></p>
|
|
146
|
+
<h1 ><Copy name="headline"></Copy></h1>
|
|
147
|
+
<p class="intro"><Copy name="intro"></Copy></p>
|
|
148
|
+
<a href="#journal" class="text-link"><Copy name="latest"></Copy>
|
|
149
|
+
↘</a></div>
|
|
150
|
+
<a href="/articles/lisbon" @click="navigate($event)"><img src="/assets/scene-1.svg" :alt="msg('p1Title')" class="hero-image" width="800" height="600" loading="lazy" />
|
|
151
|
+
<div class="image-caption"><span >01 / LISBOA</span>
|
|
152
|
+
<Copy name="read"></Copy></div></a></section>
|
|
153
|
+
<section id="journal" class="section"><div class="section-heading"><h2 ><Copy name="latest"></Copy></h2>
|
|
154
|
+
<span class="muted"><Copy name="notes"></Copy></span></div>
|
|
155
|
+
<div class="filters"><fieldset class="filter-buttons" :aria-label="msg('collection' in messages ? 'collection' : 'latest')"><button type="button" :class="state.category === 'all' ? 'chip active' : 'chip'" :aria-pressed="state.category === 'all'" @click="set('category', 'all')"><Copy name="all"></Copy></button>
|
|
156
|
+
<button type="button" :class="state.category === 'cities' ? 'chip active' : 'chip'" :aria-pressed="state.category === 'cities'" @click="set('category', 'cities')"><Copy name="cities"></Copy></button>
|
|
157
|
+
<button type="button" :class="state.category === 'nature' ? 'chip active' : 'chip'" :aria-pressed="state.category === 'nature'" @click="set('category', 'nature')"><Copy name="nature"></Copy></button>
|
|
158
|
+
<button type="button" :class="state.category === 'coast' ? 'chip active' : 'chip'" :aria-pressed="state.category === 'coast'" @click="set('category', 'coast')"><Copy name="coast"></Copy></button></fieldset>
|
|
159
|
+
<label class="search"><span class="sr-only"><Copy name="search"></Copy></span>
|
|
160
|
+
<input type="search" :placeholder="msg('search')" :value="state.query" @input="set('query', value($event))" /></label></div>
|
|
161
|
+
<div class="article-grid"><template v-for="item in visible()" :key="item.id"><article class="article-card"><a :href="detailHref(item.id)" @click="navigate($event)"><img :src="item.image" :alt="msg(item.id + 'Title')" class="" width="800" height="600" loading="lazy" /></a>
|
|
162
|
+
<div class="meta"><Copy :name="item.category"></Copy>
|
|
163
|
+
<span >{{ date(item.date) }}</span></div>
|
|
164
|
+
<h3 ><a :href="detailHref(item.id)" @click="navigate($event)"><Copy :name="item.id + 'Title'"></Copy></a></h3>
|
|
165
|
+
<p ><Copy :name="item.id + 'Summary'"></Copy></p>
|
|
166
|
+
<a :href="detailHref(item.id)" @click="navigate($event)"><Copy name="read"></Copy>
|
|
167
|
+
↗</a></article></template></div>
|
|
168
|
+
<template v-if="visible().length === 0"><div class="empty" role="status"><h3 ><Copy name="empty"></Copy></h3>
|
|
169
|
+
<p ><Copy name="emptyHint"></Copy></p>
|
|
170
|
+
<button type="button" class="button" @click="clearFilters()"><Copy name="clear"></Copy></button></div></template></section></template>
|
|
171
|
+
<template v-if="detail() !== undefined"><article class="article-detail section"><a href="/" @click="navigate($event)"><Copy name="back"></Copy></a>
|
|
172
|
+
<p class="eyebrow"><Copy :name="detail()!.category"></Copy></p>
|
|
173
|
+
<h1 ><Copy :name="detail()!.id + 'Title'"></Copy></h1>
|
|
174
|
+
<div class="meta">{{ date(detail()!.date) }}
|
|
175
|
+
<Copy name="minutes" :values="{ count: detail()!.minutes }"></Copy></div>
|
|
176
|
+
<img :src="detail()!.image" :alt="msg(detail()!.id + 'Title')" class="detail-image" width="800" height="600" loading="lazy" />
|
|
177
|
+
<div class="prose"><p class="lead"><Copy :name="detail()!.id + 'Summary'"></Copy></p>
|
|
178
|
+
<p ><Copy :name="detail()!.id + 'Body'"></Copy></p>
|
|
179
|
+
<p ><Copy :name="detail()!.id + 'End'"></Copy></p></div></article></template>
|
|
180
|
+
<template v-if="notFound()"><section class="section empty"><p class="eyebrow">404</p>
|
|
181
|
+
<h1 ><Copy name="missing"></Copy></h1>
|
|
182
|
+
<p ><Copy name="missingHint"></Copy></p>
|
|
183
|
+
<a href="/" @click="navigate($event)"><Copy name="back"></Copy></a></section></template></main>
|
|
184
|
+
<footer class="site-footer"><div ><a href="/" class="brand" @click="navigate($event)">Elsewhere</a>
|
|
185
|
+
<p ><Copy name="about"></Copy></p></div>
|
|
186
|
+
<p class="fine"><Copy name="demo"></Copy>
|
|
187
|
+
<a href="https://linguana.mohammedibrahim.dev" rel="noreferrer">Linguana ↗</a></p></footer></div>
|
|
188
|
+
</template>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { T } from "@linguanahq/vue";
|
|
3
|
+
|
|
4
|
+
defineProps<{ name: string; values?: Record<string, string | number> }>();
|
|
5
|
+
</script>
|
|
6
|
+
<template>
|
|
7
|
+
<T v-if="name === 'language'" id="language" defaultMessage="Language" :values="values" />
|
|
8
|
+
<T v-else-if="name === 'skip'" id="skip" defaultMessage="Skip to content" :values="values" />
|
|
9
|
+
<T v-else-if="name === 'home'" id="home" defaultMessage="Home" :values="values" />
|
|
10
|
+
<T v-else-if="name === 'search'" id="search" defaultMessage="Search" :values="values" />
|
|
11
|
+
<T v-else-if="name === 'all'" id="all" defaultMessage="All" :values="values" />
|
|
12
|
+
<T v-else-if="name === 'empty'" id="empty" defaultMessage="Nothing here yet." :values="values" />
|
|
13
|
+
<T v-else-if="name === 'emptyHint'" id="emptyHint" defaultMessage="Try another search or clear your filters." :values="values" />
|
|
14
|
+
<T v-else-if="name === 'clear'" id="clear" defaultMessage="Clear filters" :values="values" />
|
|
15
|
+
<T v-else-if="name === 'missing'" id="missing" defaultMessage="This page took a different path." :values="values" />
|
|
16
|
+
<T v-else-if="name === 'missingHint'" id="missingHint" defaultMessage="We could not find that page. There is plenty to discover back home." :values="values" />
|
|
17
|
+
<T v-else-if="name === 'back'" id="back" defaultMessage="Back to home" :values="values" />
|
|
18
|
+
<T v-else-if="name === 'demo'" id="demo" defaultMessage="A multilingual demo, made with Linguana." :values="values" />
|
|
19
|
+
<T v-else-if="name === 'email'" id="email" defaultMessage="Email address" :values="values" />
|
|
20
|
+
<T v-else-if="name === 'name'" id="name" defaultMessage="Your name" :values="values" />
|
|
21
|
+
<T v-else-if="name === 'simulated'" id="simulated" defaultMessage="Demo only. Your information stays in this browser." :values="values" />
|
|
22
|
+
<T v-else-if="name === 'sent'" id="sent" defaultMessage="Thank you, {name}! This was a demo; nothing was sent." :values="values" />
|
|
23
|
+
<T v-else-if="name === 'formError'" id="formError" defaultMessage="Please enter your name and a valid email address." :values="values" />
|
|
24
|
+
<T v-else-if="name === 'eyebrow'" id="eyebrow" defaultMessage="A journal of slower journeys" :values="values" />
|
|
25
|
+
<T v-else-if="name === 'headline'" id="headline" defaultMessage="Somewhere new. A little more you." :values="values" />
|
|
26
|
+
<T v-else-if="name === 'intro'" id="intro" defaultMessage="Stories from the long way round. Good coffee, unfamiliar streets, and the people who make a place." :values="values" />
|
|
27
|
+
<T v-else-if="name === 'latest'" id="latest" defaultMessage="The latest field notes" :values="values" />
|
|
28
|
+
<T v-else-if="name === 'read'" id="read" defaultMessage="Read the story" :values="values" />
|
|
29
|
+
<T v-else-if="name === 'cities'" id="cities" defaultMessage="City walks" :values="values" />
|
|
30
|
+
<T v-else-if="name === 'nature'" id="nature" defaultMessage="In the wild" :values="values" />
|
|
31
|
+
<T v-else-if="name === 'coast'" id="coast" defaultMessage="By the water" :values="values" />
|
|
32
|
+
<T v-else-if="name === 'minutes'" id="minutes" defaultMessage="{count, plural, one {# minute read} other {# minutes read}}" :values="values" />
|
|
33
|
+
<T v-else-if="name === 'notes'" id="notes" defaultMessage="Small observations. Lasting memories." :values="values" />
|
|
34
|
+
<T v-else-if="name === 'about'" id="about" defaultMessage="Elsewhere is an independent journal about travelling with curiosity and leaving room for the unexpected." :values="values" />
|
|
35
|
+
<T v-else-if="name === 'p1Title'" id="p1Title" defaultMessage="Lisbon, before the city wakes" :values="values" />
|
|
36
|
+
<T v-else-if="name === 'p1Summary'" id="p1Summary" defaultMessage="A morning of tiled doorways, warm pastries, and no particular destination." :values="values" />
|
|
37
|
+
<T v-else-if="name === 'p1Body'" id="p1Body" defaultMessage="At seven, the tram tracks are still quiet. We follow them uphill, past a florist arranging buckets on the pavement. A baker opens his window and the smell of cinnamon settles over the street. We order two coffees and a pastry, then another pastry. There is no reason to hurry." :values="values" />
|
|
38
|
+
<T v-else-if="name === 'p1End'" id="p1End" defaultMessage="By the river the light turns silver. An older couple share a newspaper on a bench, folding it between stories. We take the long route home through streets we cannot name. The best thing we found today was an hour with no plans. Come early, wear comfortable shoes, and let the hills choose your route." :values="values" />
|
|
39
|
+
<T v-else-if="name === 'p2Title'" id="p2Title" defaultMessage="A quieter side of Kyoto" :values="values" />
|
|
40
|
+
<T v-else-if="name === 'p2Summary'" id="p2Summary" defaultMessage="Beyond the busy gates, a walking route lined with small gardens." :values="values" />
|
|
41
|
+
<T v-else-if="name === 'p2Body'" id="p2Body" defaultMessage="Rain softens the sound of our footsteps along the canal. We pass a gardener sweeping leaves into a careful pile. She points us towards a small tea room with room for four people. Inside, a kettle sings and the windows fog at the edges. We warm our hands around the cups and watch the garden change colour." :values="values" />
|
|
42
|
+
<T v-else-if="name === 'p2End'" id="p2End" defaultMessage="We leave with a hand-drawn map and a recommendation to return in autumn. The canal is easy to follow, so put your phone away for a while. Keep your voice low near the houses and give the narrow paths to the people who live here. A good journey also makes room for someone else’s ordinary day." :values="values" />
|
|
43
|
+
<T v-else-if="name === 'p3Title'" id="p3Title" defaultMessage="The coastal road to nowhere" :values="values" />
|
|
44
|
+
<T v-else-if="name === 'p3Summary'" id="p3Summary" defaultMessage="Salt air and a picnic on the Atlantic edge of Portugal." :values="values" />
|
|
45
|
+
<T v-else-if="name === 'p3Body'" id="p3Body" defaultMessage="We stop the car whenever the sea disappears, just to find it again. A narrow track leads through rosemary to a beach without a sign. The sand is cool beneath our feet. Lunch is bread, tomatoes, and cheese from the last village, eaten from the paper they came wrapped in." :values="values" />
|
|
46
|
+
<T v-else-if="name === 'p3End'" id="p3End" defaultMessage="The tide comes in slowly. We pack every scrap of paper and follow our own footprints back. Check the tide before you explore, keep clear of the cliff edges, and bring more water than you think you need. The road will still be there when you are ready to leave." :values="values" />
|
|
47
|
+
<T v-else-if="name === 'p4Title'" id="p4Title" defaultMessage="Walking into the Dolomites" :values="values" />
|
|
48
|
+
<T v-else-if="name === 'p4Summary'" id="p4Summary" defaultMessage="A simple mountain hut, a shared table, and an early start." :values="values" />
|
|
49
|
+
<T v-else-if="name === 'p4Body'" id="p4Body" defaultMessage="The path begins behind a wooden barn and climbs steadily through the trees. We walk in the cool morning, stopping to hear the cowbells below. Above the tree line the mountains seem impossibly close. At the hut, soup arrives in deep bowls and strangers slide along the bench to make room." :values="values" />
|
|
50
|
+
<T v-else-if="name === 'p4End'" id="p4End" defaultMessage="Clouds gather after lunch, so we take the shorter path down. Knowing when to turn around is part of being outdoors. Ask the hut keeper about the weather, carry a proper map, and choose a trail that matches your experience. We reach the village tired, happy, and already talking about next time." :values="values" />
|
|
51
|
+
<T v-else-if="name === 'p5Title'" id="p5Title" defaultMessage="Copenhagen by bicycle" :values="values" />
|
|
52
|
+
<T v-else-if="name === 'p5Summary'" id="p5Summary" defaultMessage="Harbour dips, generous bakeries, and the city at cycling speed." :values="values" />
|
|
53
|
+
<T v-else-if="name === 'p5Body'" id="p5Body" defaultMessage="Our rented bicycles have baskets large enough for a day’s supplies. We follow the harbour, keeping to the right and letting commuters pass. The city feels different at this pace: close enough to notice a painted doorway, quick enough to follow a sudden idea across a bridge." :values="values" />
|
|
54
|
+
<T v-else-if="name === 'p5End'" id="p5End" defaultMessage="At a waterside bakery we share a cinnamon bun and mark our favourite places on a paper map. Signal before turning, lock your bicycle even for a quick stop, and leave the cycle lane clear when you pause. The best souvenir is a route you could happily ride again." :values="values" />
|
|
55
|
+
<T v-else-if="name === 'p6Title'" id="p6Title" defaultMessage="A cabin beside the lake" :values="values" />
|
|
56
|
+
<T v-else-if="name === 'p6Summary'" id="p6Summary" defaultMessage="Three days in Finland with very little on the itinerary." :values="values" />
|
|
57
|
+
<T v-else-if="name === 'p6Body'" id="p6Body" defaultMessage="The cabin key waits beneath a flowerpot. Inside there is a stove, a small shelf of books, and a window facing the lake. We fill the kettle and unpack slowly. The first afternoon passes without an event worth recording, which turns out to be exactly what we needed." :values="values" />
|
|
58
|
+
<T v-else-if="name === 'p6End'" id="p6End" defaultMessage="On the last morning we sweep the floor and leave dry wood beside the stove. There are no recommendations to collect here, just a little space to think. Bring groceries before you arrive, respect the quiet, and leave the cabin ready for the next visitor. Some places ask for less, not more." :values="values" />
|
|
59
|
+
</template>
|