From 44b0e6fb5fbebe1587a254ef469431ebacbded9a Mon Sep 17 00:00:00 2001 From: Hugo Richard Date: Wed, 17 Dec 2025 13:45:08 +0000 Subject: [PATCH 1/6] feat: make feedbacks feature a module --- app/assets/css/main.css | 1 + app/layouts/admin.vue | 5 - app/pages/docs/[...slug].vue | 2 +- modules/feedback/index.ts | 96 +++++++++++++++++++ .../feedback/runtime/components/Chart.vue | 15 +-- .../feedback/runtime/components/Dashboard.vue | 10 +- .../runtime/components/DatePicker.vue | 0 .../feedback/runtime/components/Item.vue | 2 + .../feedback/runtime/components/StatCard.vue | 0 .../feedback/runtime/components/Widget.vue | 1 + .../runtime}/composables/useDateRange.ts | 0 .../runtime}/composables/useFeedback.ts | 13 ++- .../runtime}/composables/useFeedbackExport.ts | 3 + .../feedback/runtime}/middleware/auth.ts | 3 +- .../feedback/runtime}/middleware/guest.ts | 3 +- .../feedback/runtime}/pages/admin/index.vue | 6 +- .../feedback/runtime}/pages/admin/login.vue | 14 +-- .../runtime/server/api/auth/github.get.ts | 16 ++++ .../server}/api/feedback/[id].delete.ts | 1 + .../runtime/server}/api/feedback/index.get.ts | 2 + .../server}/api/feedback/index.post.ts | 7 +- .../runtime/server/db/schema.sqlite.ts | 0 .../feedback/runtime/shared/types/feedback.ts | 5 + .../feedback.ts => modules/feedback/types.ts | 40 ++++++++ modules/local.ts | 11 ++- nuxt.config.ts | 5 +- server/api/auth/github.get.ts | 12 --- server/plugins/feedback-auth.ts | 7 ++ 28 files changed, 220 insertions(+), 60 deletions(-) delete mode 100644 app/layouts/admin.vue create mode 100644 modules/feedback/index.ts rename app/components/feedback/FeedbackChart.vue => modules/feedback/runtime/components/Chart.vue (98%) rename app/components/AdminDashboard.vue => modules/feedback/runtime/components/Dashboard.vue (98%) rename app/components/feedback/FeedbackDatePicker.vue => modules/feedback/runtime/components/DatePicker.vue (100%) rename app/components/feedback/FeedbackItem.vue => modules/feedback/runtime/components/Item.vue (97%) rename app/components/feedback/FeedbackStatCard.vue => modules/feedback/runtime/components/StatCard.vue (100%) rename app/components/Feedback.vue => modules/feedback/runtime/components/Widget.vue (99%) rename {app => modules/feedback/runtime}/composables/useDateRange.ts (100%) rename {app => modules/feedback/runtime}/composables/useFeedback.ts (96%) rename {app => modules/feedback/runtime}/composables/useFeedbackExport.ts (97%) rename {app => modules/feedback/runtime}/middleware/auth.ts (53%) rename {app => modules/feedback/runtime}/middleware/guest.ts (55%) rename {app => modules/feedback/runtime}/pages/admin/index.vue (78%) rename {app => modules/feedback/runtime}/pages/admin/login.vue (85%) create mode 100644 modules/feedback/runtime/server/api/auth/github.get.ts rename {server => modules/feedback/runtime/server}/api/feedback/[id].delete.ts (94%) rename {server => modules/feedback/runtime/server}/api/feedback/index.get.ts (79%) rename {server => modules/feedback/runtime/server}/api/feedback/index.post.ts (84%) rename server/db/schema.ts => modules/feedback/runtime/server/db/schema.sqlite.ts (100%) create mode 100644 modules/feedback/runtime/shared/types/feedback.ts rename shared/types/feedback.ts => modules/feedback/types.ts (67%) delete mode 100644 server/api/auth/github.get.ts create mode 100644 server/plugins/feedback-auth.ts diff --git a/app/assets/css/main.css b/app/assets/css/main.css index 8e52533a4..7af53fb6a 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -3,6 +3,7 @@ @source "../../../content/**/*"; @source "../../../node_modules/.c12"; +@source "../../../modules/"; @theme static { --font-sans: 'Public Sans', sans-serif; diff --git a/app/layouts/admin.vue b/app/layouts/admin.vue deleted file mode 100644 index 56a8b72d4..000000000 --- a/app/layouts/admin.vue +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/app/pages/docs/[...slug].vue b/app/pages/docs/[...slug].vue index 7fc41a8fd..78507644f 100644 --- a/app/pages/docs/[...slug].vue +++ b/app/pages/docs/[...slug].vue @@ -191,7 +191,7 @@ function refreshHeading(opened: boolean) {
- +
({ + meta: { + name: 'feedback', + configKey: 'feedback' + }, + defaults: { + adminPath: '/_feedback/admin' + }, + async setup(options, nuxt) { + const { resolve } = createResolver(import.meta.url) + const adminPath = options.adminPath!.replace(/\/$/, '') + + nuxt.options.runtimeConfig.public.feedback = { + adminPath + } + + nuxt.hook('hub:db:schema:extend', async ({ dialect, paths }: { dialect: string, paths: string[] }) => { + if (dialect === 'sqlite') { + paths.push(resolve('./runtime/server/db/schema.sqlite.ts')) + } + }) + + addComponentsDir({ + path: resolve('./runtime/components'), + prefix: 'Feedback' + }) + + addImportsDir(resolve('./runtime/composables')) + + addServerImportsDir(resolve('./runtime/server/utils')) + + addServerHandler({ + route: '/api/_feedback', + method: 'get', + handler: resolve('./runtime/server/api/feedback/index.get') + }) + + addServerHandler({ + route: '/api/_feedback', + method: 'post', + handler: resolve('./runtime/server/api/feedback/index.post') + }) + + addServerHandler({ + route: '/api/_feedback/:id', + method: 'delete', + handler: resolve('./runtime/server/api/feedback/[id].delete') + }) + + addServerHandler({ + route: '/api/auth/github', + method: 'get', + handler: resolve('./runtime/server/api/auth/github.get') + }) + + addRouteMiddleware({ + name: 'feedback-auth', + path: resolve('./runtime/middleware/auth') + }) + + addRouteMiddleware({ + name: 'feedback-guest', + path: resolve('./runtime/middleware/guest') + }) + + extendPages((pages) => { + pages.push({ + name: 'feedback-admin', + path: adminPath, + file: resolve('./runtime/pages/admin/index.vue') + }) + + pages.push({ + name: 'feedback-admin-login', + path: `${adminPath}/login`, + file: resolve('./runtime/pages/admin/login.vue') + }) + }) + + nuxt.options.routeRules[adminPath] = { ssr: false } + nuxt.options.routeRules[`${adminPath}/**`] = { ssr: false } + + nuxt.hook('prepare:types', ({ references }) => { + references.push({ + path: resolve('./types.ts') + }) + }) + } +}) + +export type { FeedbackModuleOptions } from './types' +export { FEEDBACK_OPTIONS, FEEDBACK_RATINGS, feedbackSchema, feedbackFormSchema } from './types' +export type { FeedbackRating, FeedbackItem, FeedbackSubmission, PageAnalytic, FeedbackInput } from './types' diff --git a/app/components/feedback/FeedbackChart.vue b/modules/feedback/runtime/components/Chart.vue similarity index 98% rename from app/components/feedback/FeedbackChart.vue rename to modules/feedback/runtime/components/Chart.vue index d3dadfed8..c0d3a4d77 100644 --- a/app/components/feedback/FeedbackChart.vue +++ b/modules/feedback/runtime/components/Chart.vue @@ -1,16 +1,7 @@ diff --git a/app/pages/admin/login.vue b/modules/feedback/runtime/pages/admin/login.vue similarity index 85% rename from app/pages/admin/login.vue rename to modules/feedback/runtime/pages/admin/login.vue index 5ee516add..b79bc1322 100644 --- a/app/pages/admin/login.vue +++ b/modules/feedback/runtime/pages/admin/login.vue @@ -3,7 +3,7 @@ import { motion } from 'motion-v' definePageMeta({ layout: false, - middleware: 'guest', + middleware: 'feedback-guest', colorMode: 'dark' }) @@ -12,7 +12,7 @@ const errorType = route.query.error as string