@ykdz/template 0.0.12 → 0.0.13

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.
Files changed (38) hide show
  1. package/node_modules/@ykdz/template-builtin-source/dist/templates/registry.js +2 -0
  2. package/node_modules/@ykdz/template-builtin-source/dist/templates/vike-app/projection.d.ts +5 -0
  3. package/node_modules/@ykdz/template-builtin-source/dist/templates/vike-app/projection.js +57 -0
  4. package/node_modules/@ykdz/template-builtin-source/templates/preset-source.json +176 -0
  5. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/+server.ts +12 -0
  6. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/.env.example +1 -0
  7. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/.github/dependabot.yml +23 -0
  8. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/.github/workflows/check.yml +20 -0
  9. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/assets/logo.svg +1 -0
  10. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/components/CounterButton.vue +21 -0
  11. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/components/PageShell.vue +17 -0
  12. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/database/db.ts +14 -0
  13. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/database/queries/todos.ts +32 -0
  14. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/database/schema.ts +14 -0
  15. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/drizzle.config.ts +10 -0
  16. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/env.d.ts +6 -0
  17. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/global.d.ts +9 -0
  18. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/pages/+Head.vue +8 -0
  19. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/pages/+Layout.vue +9 -0
  20. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/pages/+config.ts +10 -0
  21. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/pages/index/+Page.telefunc.ts +13 -0
  22. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/pages/index/+Page.vue +89 -0
  23. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/pages/tailwind.css +7 -0
  24. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/playwright.config.ts +22 -0
  25. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/server/api.ts +5 -0
  26. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/server/app.ts +25 -0
  27. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/test/e2e/app.spec.ts +10 -0
  28. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/test/todos.test.ts +20 -0
  29. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/vite.config.ts +12 -0
  30. package/node_modules/@ykdz/template-builtin-source/templates/vike-app/vitest.config.ts +8 -0
  31. package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/web/src/api.ts +1 -4
  32. package/node_modules/@ykdz/template-core/dist/package-addition.js +2 -1
  33. package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +6 -0
  34. package/node_modules/@ykdz/template-core/dist/projection-capabilities.d.ts +1 -1
  35. package/node_modules/@ykdz/template-core/dist/projection-capabilities.js +227 -22
  36. package/node_modules/@ykdz/template-shared/dist/index.d.ts +9 -9
  37. package/node_modules/@ykdz/template-shared/dist/index.js +29 -11
  38. package/package.json +3 -3
@@ -1,12 +1,14 @@
1
1
  import { honoApiPresetProjection } from "./hono-api/projection.js";
2
2
  import { rustBinPresetProjection } from "./rust-bin/projection.js";
3
3
  import { tsLibPresetProjection } from "./ts-lib/projection.js";
4
+ import { vikeAppPresetProjection } from "./vike-app/projection.js";
4
5
  import { vueAppPresetProjection } from "./vue-app/projection.js";
5
6
  import { vueHonoAppPresetProjection } from "./vue-hono-app/projection.js";
6
7
  const testOnlyPresetProjections = [
7
8
  tsLibPresetProjection,
8
9
  honoApiPresetProjection,
9
10
  vueAppPresetProjection,
11
+ vikeAppPresetProjection,
10
12
  vueHonoAppPresetProjection,
11
13
  rustBinPresetProjection,
12
14
  ];
@@ -0,0 +1,5 @@
1
+ import type { PresetBlueprintOptions, PresetProjection } from "@ykdz/template-core/preset-projection";
2
+ import { type BuiltInPreset, type ProjectBlueprint } from "@ykdz/template-shared";
3
+ export declare const vikeAppPresetMetadata: BuiltInPreset;
4
+ export declare function vikeAppBlueprint(options?: PresetBlueprintOptions): ProjectBlueprint;
5
+ export declare const vikeAppPresetProjection: PresetProjection;
@@ -0,0 +1,57 @@
1
+ import { builtInPresetProjectionSourceRoots, loadBuiltInPresetProjectionDeclaration, } from "@ykdz/template-builtin-source";
2
+ import { interpretPresetProjectionDeclaration } from "@ykdz/template-core/projection-capabilities";
3
+ import { renderNewProject } from "@ykdz/template-core/renderer";
4
+ import { PackageAdditionSupport, } from "@ykdz/template-shared";
5
+ export const vikeAppPresetMetadata = {
6
+ name: "vike-app",
7
+ title: "Vike app",
8
+ description: "Single-package Vike, Hono, Telefunc, Drizzle, and Vue application.",
9
+ generation: "supported",
10
+ supportedPackageManagers: ["pnpm"],
11
+ supportedProjectKinds: ["multi-package"],
12
+ packageAdditionSupport: PackageAdditionSupport.Unsupported,
13
+ features: [
14
+ "pnpm-catalog",
15
+ "oxc-format-lint",
16
+ "strict-typescript",
17
+ "root-check",
18
+ "fix-command",
19
+ "devcontainer",
20
+ "github-actions",
21
+ "dependabot",
22
+ ],
23
+ };
24
+ function projectNameFromDir(targetDir) {
25
+ return targetDir.split(/[\\/]/).filter(Boolean).at(-1) ?? "vike-app";
26
+ }
27
+ export function vikeAppBlueprint(options = { targetDir: process.cwd() }) {
28
+ const projectName = projectNameFromDir(options.targetDir);
29
+ return {
30
+ schemaVersion: 1,
31
+ preset: "vike-app",
32
+ packageManager: "pnpm",
33
+ projectKind: "multi-package",
34
+ features: [...vikeAppPresetMetadata.features],
35
+ packages: [{ name: projectName, path: "." }],
36
+ };
37
+ }
38
+ export const vikeAppPresetProjection = {
39
+ metadata: vikeAppPresetMetadata,
40
+ blueprint: vikeAppBlueprint,
41
+ project(context) {
42
+ return interpretPresetProjectionDeclaration({
43
+ preset: vikeAppPresetMetadata,
44
+ declaration: loadBuiltInPresetProjectionDeclaration("vike-app"),
45
+ context,
46
+ sourceRoots: builtInPresetProjectionSourceRoots(),
47
+ });
48
+ },
49
+ async render({ targetDir, plan }) {
50
+ await renderNewProject({
51
+ sourceRoot: plan.sourceRoot,
52
+ sourceRoots: plan.sourceRoots,
53
+ targetRoot: targetDir,
54
+ operations: [...plan.operations],
55
+ });
56
+ },
57
+ };
@@ -32,6 +32,7 @@
32
32
  { "preset": "ts-lib" },
33
33
  { "preset": "hono-api" },
34
34
  { "preset": "vue-app" },
35
+ { "preset": "vike-app" },
35
36
  { "preset": "vue-hono-app" },
36
37
  { "preset": "rust-bin" }
37
38
  ],
@@ -77,6 +78,11 @@
77
78
  "addedPreset": "vue-hono-app",
78
79
  "reason": "vue-hono-app is an initialization-only full-stack preset."
79
80
  },
81
+ {
82
+ "basePreset": "ts-lib",
83
+ "addedPreset": "vike-app",
84
+ "reason": "vike-app is an initialization-only root application preset."
85
+ },
80
86
  {
81
87
  "basePreset": "ts-lib",
82
88
  "addedPreset": "rust-bin",
@@ -87,6 +93,11 @@
87
93
  "addedPreset": "vue-hono-app",
88
94
  "reason": "vue-hono-app is an initialization-only full-stack preset."
89
95
  },
96
+ {
97
+ "basePreset": "hono-api",
98
+ "addedPreset": "vike-app",
99
+ "reason": "vike-app is an initialization-only root application preset."
100
+ },
90
101
  {
91
102
  "basePreset": "hono-api",
92
103
  "addedPreset": "rust-bin",
@@ -97,6 +108,51 @@
97
108
  "addedPreset": "vue-hono-app",
98
109
  "reason": "vue-hono-app is an initialization-only full-stack preset."
99
110
  },
111
+ {
112
+ "basePreset": "vue-app",
113
+ "addedPreset": "vike-app",
114
+ "reason": "vike-app is an initialization-only root application preset."
115
+ },
116
+ {
117
+ "basePreset": "vike-app",
118
+ "addedPreset": "ts-lib",
119
+ "reason": "vike-app is an initialization-only root application preset."
120
+ },
121
+ {
122
+ "basePreset": "vike-app",
123
+ "addedPreset": "hono-api",
124
+ "reason": "vike-app is an initialization-only root application preset."
125
+ },
126
+ {
127
+ "basePreset": "vike-app",
128
+ "addedPreset": "vue-app",
129
+ "reason": "vike-app is an initialization-only root application preset."
130
+ },
131
+ {
132
+ "basePreset": "vike-app",
133
+ "addedPreset": "vike-app",
134
+ "reason": "vike-app is an initialization-only root application preset."
135
+ },
136
+ {
137
+ "basePreset": "vike-app",
138
+ "addedPreset": "vue-hono-app",
139
+ "reason": "vue-hono-app is an initialization-only full-stack preset."
140
+ },
141
+ {
142
+ "basePreset": "vike-app",
143
+ "addedPreset": "rust-bin",
144
+ "reason": "rust-bin is an initialization-only native binary preset."
145
+ },
146
+ {
147
+ "basePreset": "vue-hono-app",
148
+ "addedPreset": "vike-app",
149
+ "reason": "vike-app is an initialization-only root application preset."
150
+ },
151
+ {
152
+ "basePreset": "rust-bin",
153
+ "addedPreset": "vike-app",
154
+ "reason": "vike-app is an initialization-only root application preset."
155
+ },
100
156
  {
101
157
  "basePreset": "vue-app",
102
158
  "addedPreset": "rust-bin",
@@ -353,6 +409,126 @@
353
409
  ]
354
410
  }
355
411
  },
412
+ {
413
+ "name": "vike-app",
414
+ "title": "Vike app",
415
+ "description": "Single-package Vike, Hono, Telefunc, Drizzle, and Vue application.",
416
+ "generation": "supported",
417
+ "supportedPackageManagers": ["pnpm"],
418
+ "supportedProjectKinds": ["multi-package"],
419
+ "packageAdditionSupport": "unsupported",
420
+ "features": [
421
+ "pnpm-catalog",
422
+ "oxc-format-lint",
423
+ "strict-typescript",
424
+ "root-check",
425
+ "fix-command",
426
+ "devcontainer",
427
+ "github-actions",
428
+ "dependabot"
429
+ ],
430
+ "dependencyCatalog": [
431
+ "@playwright/test",
432
+ "@tailwindcss/vite",
433
+ "@types/node",
434
+ "@vitejs/plugin-vue",
435
+ "@vikejs/hono",
436
+ "@vue/tsconfig",
437
+ "drizzle-kit",
438
+ "drizzle-orm",
439
+ "hono",
440
+ "oxfmt",
441
+ "oxlint",
442
+ "oxlint-tsgolint",
443
+ "tailwindcss",
444
+ "telefunc",
445
+ "typescript",
446
+ "vite",
447
+ "vike",
448
+ "vike-vue",
449
+ "vitest",
450
+ "vue",
451
+ "vue-tsc"
452
+ ],
453
+ "projection": {
454
+ "capabilities": [
455
+ {
456
+ "kind": "workspace-node-packages",
457
+ "workspacePackageGlob": ".",
458
+ "packages": [
459
+ {
460
+ "kind": "vike-app",
461
+ "path": ".",
462
+ "sourceFiles": [
463
+ "+server.ts",
464
+ ".env.example",
465
+ "assets/logo.svg",
466
+ "components/CounterButton.vue",
467
+ "components/PageShell.vue",
468
+ "database/db.ts",
469
+ "database/queries/todos.ts",
470
+ "database/schema.ts",
471
+ "drizzle.config.ts",
472
+ "env.d.ts",
473
+ "global.d.ts",
474
+ "pages/+Head.vue",
475
+ "pages/+Layout.vue",
476
+ "pages/+config.ts",
477
+ "pages/index/+Page.vue",
478
+ "pages/index/+Page.telefunc.ts",
479
+ "pages/tailwind.css",
480
+ "playwright.config.ts",
481
+ "server/api.ts",
482
+ "server/app.ts",
483
+ "test/e2e/app.spec.ts",
484
+ "test/todos.test.ts",
485
+ "vite.config.ts",
486
+ "vitest.config.ts"
487
+ ]
488
+ }
489
+ ]
490
+ },
491
+ { "kind": "strict-typescript-root" },
492
+ {
493
+ "kind": "oxc-format-lint",
494
+ "editorCustomizationResourceId": "shared-editor-customization"
495
+ },
496
+ {
497
+ "kind": "node-pnpm-devcontainer",
498
+ "devcontainerResourceId": "shared-devcontainer"
499
+ },
500
+ { "kind": "github-maintenance" }
501
+ ]
502
+ },
503
+ "source": {
504
+ "roots": [
505
+ "vike-app/.github",
506
+ "vike-app/assets",
507
+ "vike-app/components",
508
+ "vike-app/database",
509
+ "vike-app/pages",
510
+ "vike-app/server",
511
+ "vike-app/test"
512
+ ],
513
+ "files": [
514
+ "vike-app/+server.ts",
515
+ "vike-app/.env.example",
516
+ "vike-app/drizzle.config.ts",
517
+ "vike-app/env.d.ts",
518
+ "vike-app/global.d.ts",
519
+ "vike-app/playwright.config.ts",
520
+ "vike-app/vite.config.ts",
521
+ "vike-app/vitest.config.ts"
522
+ ],
523
+ "sharedResources": [
524
+ "shared-devcontainer",
525
+ "shared-editor-customization",
526
+ "shared-oxc-format",
527
+ "shared-oxc-root-tsconfig",
528
+ "shared-oxc-vue"
529
+ ]
530
+ }
531
+ },
356
532
  {
357
533
  "name": "vue-hono-app",
358
534
  "title": "Vue Hono app",
@@ -0,0 +1,12 @@
1
+ import type { Server } from "vike/types";
2
+
3
+ import { app } from "#/server/app";
4
+
5
+ const port = Number.parseInt(process.env.PORT ?? "3000", 10);
6
+
7
+ export default {
8
+ fetch: app.fetch,
9
+ prod: {
10
+ port,
11
+ },
12
+ } satisfies Server;
@@ -0,0 +1 @@
1
+ DATABASE_FILE=./data/app.sqlite
@@ -0,0 +1,23 @@
1
+ version: 2
2
+
3
+ updates:
4
+ - package-ecosystem: npm
5
+ directory: /
6
+ schedule:
7
+ interval: weekly
8
+ ignore:
9
+ - dependency-name: "@types/node"
10
+ update-types:
11
+ - version-update:semver-major
12
+ - package-ecosystem: github-actions
13
+ directory: /
14
+ schedule:
15
+ interval: weekly
16
+ - package-ecosystem: docker
17
+ directory: /.devcontainer
18
+ schedule:
19
+ interval: weekly
20
+ ignore:
21
+ - dependency-name: mcr.microsoft.com/devcontainers/typescript-node
22
+ update-types:
23
+ - version-update:semver-major
@@ -0,0 +1,20 @@
1
+ name: Check
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - main
8
+
9
+ jobs:
10
+ check:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v6
14
+ - uses: actions/setup-node@v6
15
+ with:
16
+ node-version-file: package.json
17
+ - run: corepack enable
18
+ - run: pnpm install
19
+ - run: pnpm exec playwright install --with-deps chromium
20
+ - run: pnpm run check
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 32 32"><g fill="none"><path fill="#9B9B9B" d="m10.38 29.104l12.9.99a3.4 3.4 0 0 0 2.74-1.38l3.18-4.3c.56-.77.78-1.74.59-2.67l-.505-2.563l-1.165-.837l-.335-2.7l.696-.543l-.031-.157c-.16-.82-.61-1.55-1.28-2.05l-3.79-3.37l-2.38-4.4l-2.9-.16l-5.06-1.84l-6.66 7.04l-1.61 3.61l-.26.58l-1.66 3.07c-.17.3.02 3.08-.04 3.42c0 0 6.95 8.26 7.57 8.26"/><path fill="#E6E6E6" d="m20 10.104l-4.05 11.14l9.71 2.7l3.63-4.77l-.81-4.07z"/><path fill="#636363" d="M2.51 18.394L2 22.104h3l.79-3.13c.13-.56.48-1.03.97-1.33l4.24-2.54l-3.05-6.66l-1.38 1.51c-.13.14-.23.3-.31.48l-1.75 3.93l-1.66 3.07c-.17.3-.28.62-.34.96"/><path fill="#D3D3D3" d="m11.51 20.614l4.49 4.49l9.66-1.16l-7.48-3.4c-.66-.3-1-1.05-.79-1.75l2.61-8.69l1-4.98c-.84-1.34-1.23-1.72-2.67-2.19c-.96-.34-1.79-.63-1.79-.63s-.54-.23-1.12-.29c-.73-.06-1.2.07-1.82.54L11 15.104v4.28c0 .46.18.9.51 1.23"/><path fill="#636363" d="M2 22.104h3l11 3v4.99l-4.25.01c-1.15 0-2.28-.26-3.31-.78l-1.37-.68a7.2 7.2 0 0 1-1.91-1.38l-.93-.93a7.3 7.3 0 0 1-1.78-2.88z"/><path fill="#9B9B9B" d="M29.98 22.914c.12.66-.06 1.34-.51 1.85l-3.97 4.52c-.41.47-1.17.81-1.79.82H16v-5l9.66-1.16l3.62-4.77zM17.51 4.434l-1.11-1.57a1.883 1.883 0 0 0-2.89-.22l-6.76 7.04c-.65.68-.53 1.79.25 2.31l4 3.11l4.63-4.21c.55-.5.95-1.14 1.16-1.86l.95-3.25c.13-.46.05-.96-.23-1.35"/></g></svg>
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ import { onMounted, ref } from "vue";
3
+
4
+ const count = ref(0);
5
+ const mounted = ref(false);
6
+
7
+ onMounted(() => {
8
+ mounted.value = true;
9
+ });
10
+ </script>
11
+
12
+ <template>
13
+ <button
14
+ type="button"
15
+ class="rounded border border-slate-900 bg-white px-3 py-1 text-sm font-medium text-slate-900 shadow-sm disabled:cursor-wait disabled:opacity-60"
16
+ :disabled="!mounted"
17
+ @click="count += 1"
18
+ >
19
+ Count {{ count }}
20
+ </button>
21
+ </template>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import logoUrl from "#/assets/logo.svg";
3
+ </script>
4
+
5
+ <template>
6
+ <div class="min-h-screen bg-slate-50 text-slate-950">
7
+ <header class="border-b border-slate-200 bg-white">
8
+ <nav class="mx-auto flex max-w-4xl items-center gap-3 px-6 py-4">
9
+ <img :src="logoUrl" alt="" class="size-8" />
10
+ <a href="/" class="font-semibold text-slate-950">Vike App</a>
11
+ </nav>
12
+ </header>
13
+ <main class="mx-auto max-w-4xl px-6 py-10">
14
+ <slot />
15
+ </main>
16
+ </div>
17
+ </template>
@@ -0,0 +1,14 @@
1
+ import { mkdirSync } from "node:fs";
2
+ import path from "node:path";
3
+
4
+ import { drizzle } from "drizzle-orm/node-sqlite";
5
+
6
+ import * as schema from "#/database/schema";
7
+
8
+ export type Database = ReturnType<typeof createDatabase>;
9
+
10
+ export function createDatabase(databaseFile = process.env.DATABASE_FILE) {
11
+ const file = databaseFile ?? "./data/app.sqlite";
12
+ mkdirSync(path.dirname(file), { recursive: true });
13
+ return drizzle(file, { schema });
14
+ }
@@ -0,0 +1,32 @@
1
+ import { desc, eq } from "drizzle-orm";
2
+
3
+ import type { Database } from "#/database/db";
4
+ import { todos, type NewTodo } from "#/database/schema";
5
+
6
+ export async function listTodos(db: Database) {
7
+ return db.select().from(todos).orderBy(desc(todos.createdAt));
8
+ }
9
+
10
+ export async function createTodo(db: Database, values: NewTodo) {
11
+ const [todo] = await db.insert(todos).values(values).returning();
12
+
13
+ if (!todo) {
14
+ throw new Error("Failed to create todo");
15
+ }
16
+
17
+ return todo;
18
+ }
19
+
20
+ export async function completeTodo(db: Database, id: number) {
21
+ const [todo] = await db
22
+ .update(todos)
23
+ .set({ completed: true })
24
+ .where(eq(todos.id, id))
25
+ .returning();
26
+
27
+ if (!todo) {
28
+ throw new Error(`Todo ${id} was not found`);
29
+ }
30
+
31
+ return todo;
32
+ }
@@ -0,0 +1,14 @@
1
+ import { sql } from "drizzle-orm";
2
+ import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
3
+
4
+ export const todos = sqliteTable("todos", {
5
+ id: integer({ mode: "number" }).primaryKey({ autoIncrement: true }),
6
+ title: text().notNull(),
7
+ completed: integer({ mode: "boolean" }).default(false).notNull(),
8
+ createdAt: text("created_at")
9
+ .default(sql`(CURRENT_TIMESTAMP)`)
10
+ .notNull(),
11
+ });
12
+
13
+ export type Todo = typeof todos.$inferSelect;
14
+ export type NewTodo = typeof todos.$inferInsert;
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "drizzle-kit";
2
+
3
+ export default defineConfig({
4
+ dialect: "sqlite",
5
+ schema: "./database/schema.ts",
6
+ out: "./database/migrations",
7
+ dbCredentials: {
8
+ url: process.env.DATABASE_FILE ?? "./data/app.sqlite",
9
+ },
10
+ });
@@ -0,0 +1,6 @@
1
+ declare module "*.css";
2
+
3
+ declare module "*.svg" {
4
+ const url: string;
5
+ export default url;
6
+ }
@@ -0,0 +1,9 @@
1
+ import type { Database } from "#/database/db";
2
+
3
+ declare global {
4
+ namespace Telefunc {
5
+ interface Context {
6
+ db: Database;
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,8 @@
1
+ <script setup lang="ts">
2
+ import "./tailwind.css";
3
+ import logoUrl from "#/assets/logo.svg";
4
+ </script>
5
+
6
+ <template>
7
+ <link rel="icon" :href="logoUrl" />
8
+ </template>
@@ -0,0 +1,9 @@
1
+ <script setup lang="ts">
2
+ import PageShell from "#/components/PageShell.vue";
3
+ </script>
4
+
5
+ <template>
6
+ <PageShell>
7
+ <slot />
8
+ </PageShell>
9
+ </template>
@@ -0,0 +1,10 @@
1
+ import vikeVue from "vike-vue/config";
2
+ import type { Config } from "vike/types";
3
+
4
+ const config: Config = {
5
+ title: "Vike App",
6
+ description: "Vike, Hono, Telefunc, Drizzle, and Vue.",
7
+ extends: [vikeVue],
8
+ };
9
+
10
+ export default config;
@@ -0,0 +1,13 @@
1
+ import { getContext } from "telefunc";
2
+
3
+ import { createTodo, listTodos } from "#/database/queries/todos";
4
+
5
+ export async function onLoadTodos() {
6
+ const { db } = getContext();
7
+ return listTodos(db);
8
+ }
9
+
10
+ export async function onAddTodo(title: string) {
11
+ const { db } = getContext();
12
+ return createTodo(db, { title });
13
+ }
@@ -0,0 +1,89 @@
1
+ <script setup lang="ts">
2
+ import { ref } from "vue";
3
+
4
+ import CounterButton from "#/components/CounterButton.vue";
5
+ import type { Todo } from "#/database/schema";
6
+
7
+ import { onAddTodo, onLoadTodos } from "./+Page.telefunc";
8
+
9
+ const title = ref("");
10
+ const todos = ref<Todo[]>([]);
11
+ const error = ref<string | undefined>();
12
+
13
+ async function refreshTodos() {
14
+ error.value = undefined;
15
+
16
+ try {
17
+ todos.value = await onLoadTodos();
18
+ } catch (unknownError) {
19
+ error.value =
20
+ unknownError instanceof Error
21
+ ? unknownError.message
22
+ : "Unable to load todos";
23
+ }
24
+ }
25
+
26
+ async function submitTodo() {
27
+ const nextTitle = title.value.trim();
28
+ if (nextTitle.length === 0) {
29
+ return;
30
+ }
31
+
32
+ await onAddTodo(nextTitle);
33
+ title.value = "";
34
+ await refreshTodos();
35
+ }
36
+ </script>
37
+
38
+ <template>
39
+ <section class="grid gap-8">
40
+ <div class="grid gap-4">
41
+ <p class="text-sm font-semibold tracking-wide text-rose-600 uppercase">
42
+ Vike + Hono
43
+ </p>
44
+ <h1 class="text-4xl font-bold tracking-tight">Full-stack Vike app</h1>
45
+ <p class="max-w-2xl text-lg text-slate-700">
46
+ Server-rendered Vue with Hono routing, Telefunc actions, and Drizzle
47
+ database access.
48
+ </p>
49
+ <CounterButton />
50
+ </div>
51
+
52
+ <form class="flex max-w-xl gap-2" @submit.prevent="submitTodo">
53
+ <input
54
+ v-model="title"
55
+ class="min-w-0 flex-1 rounded border border-slate-300 px-3 py-2"
56
+ name="title"
57
+ placeholder="Add a database-backed todo"
58
+ />
59
+ <button class="rounded bg-slate-950 px-4 py-2 text-white" type="submit">
60
+ Add
61
+ </button>
62
+ </form>
63
+
64
+ <button
65
+ class="w-fit text-sm font-medium text-rose-700"
66
+ type="button"
67
+ @click="refreshTodos"
68
+ >
69
+ Load todos
70
+ </button>
71
+
72
+ <p
73
+ v-if="error"
74
+ class="max-w-xl rounded border border-amber-300 bg-amber-50 p-3 text-sm"
75
+ >
76
+ {{ error }}
77
+ </p>
78
+
79
+ <ul v-if="todos.length > 0" class="grid max-w-xl gap-2">
80
+ <li
81
+ v-for="todo in todos"
82
+ :key="todo.id"
83
+ class="rounded border border-slate-200 bg-white px-3 py-2"
84
+ >
85
+ {{ todo.title }}
86
+ </li>
87
+ </ul>
88
+ </section>
89
+ </template>
@@ -0,0 +1,7 @@
1
+ @import "tailwindcss";
2
+
3
+ @layer base {
4
+ body {
5
+ margin: 0;
6
+ }
7
+ }
@@ -0,0 +1,22 @@
1
+ import { defineConfig, devices } from "@playwright/test";
2
+
3
+ const previewUrl = "http://127.0.0.1:4173";
4
+
5
+ export default defineConfig({
6
+ testDir: "./test/e2e",
7
+ use: {
8
+ baseURL: previewUrl,
9
+ trace: "on-first-retry",
10
+ },
11
+ webServer: {
12
+ command: "PORT=4173 node dist/server/index.mjs",
13
+ reuseExistingServer: !process.env.CI,
14
+ url: previewUrl,
15
+ },
16
+ projects: [
17
+ {
18
+ name: "chromium",
19
+ use: { ...devices["Desktop Chrome"] },
20
+ },
21
+ ],
22
+ });
@@ -0,0 +1,5 @@
1
+ import { Hono } from "hono";
2
+
3
+ export const api = new Hono().get("/health", (c) =>
4
+ c.json({ ok: true, service: "vike-app" }),
5
+ );