diff --git a/.gitignore b/.gitignore index 3285614..118d70d 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ build .nuxt .kotlin .wrangler +.data # IntelliJ .idea/ diff --git a/apps/frontend/.env.example b/apps/frontend/.env.example index 12a985f..d05b08a 100644 --- a/apps/frontend/.env.example +++ b/apps/frontend/.env.example @@ -1,2 +1,7 @@ -NUXT_PUBLIC_SITE_URL= NUXT_PUBLIC_API_BASE_URL= + +NUXT_SITE_URL= +NUXT_SITE_NAME= + +# Must be: development, staging or production +NUXT_SITE_ENV= diff --git a/apps/frontend/.env.local b/apps/frontend/.env.local index 805100d..9b906dc 100644 --- a/apps/frontend/.env.local +++ b/apps/frontend/.env.local @@ -1,3 +1,5 @@ -NUXT_PUBLIC_SITE_URL=http://localhost:3000 NUXT_PUBLIC_API_BASE_URL=http://localhost:8080 -NUXT_PUBLIC_PREVIEW=false + +NUXT_SITE_URL=http://localhost:3000 +NUXT_SITE_NAME=Solitar +NUXT_SITE_ENV=development diff --git a/apps/frontend/.nuxtrc b/apps/frontend/.nuxtrc deleted file mode 100644 index 1e1fe83..0000000 --- a/apps/frontend/.nuxtrc +++ /dev/null @@ -1 +0,0 @@ -setups.@nuxt/test-utils="4.0.0" \ No newline at end of file diff --git a/apps/frontend/app/app.config.ts b/apps/frontend/app/app.config.ts deleted file mode 100644 index faa4221..0000000 --- a/apps/frontend/app/app.config.ts +++ /dev/null @@ -1,51 +0,0 @@ -export default defineAppConfig({ - ui: { - colors: { - primary: "teal", - }, - icons: { - arrowDown: "i-tabler-arrow-down", - arrowLeft: "i-tabler-arrow-left", - arrowRight: "i-tabler-arrow-right", - arrowUp: "i-tabler-arrow-up", - caution: "i-tabler-alert-square-rounded", - check: "i-tabler-check", - chevronDoubleLeft: "i-tabler-chevrons-left", - chevronDoubleRight: "i-tabler-chevrons-right", - chevronDown: "i-tabler-chevron-down", - chevronLeft: "i-tabler-chevron-left", - chevronRight: "i-tabler-chevron-right", - chevronUp: "i-tabler-chevron-up", - close: "i-tabler-x", - copy: "i-tabler-copy", - copyCheck: "i-tabler-copy-check", - dark: "i-tabler-moon", - drag: "i-tabler-grip-vertical", - ellipsis: "i-tabler-dots", - error: "i-tabler-square-rounded-x", - external: "i-tabler-external-link", - eye: "i-tabler-eye", - eyeOff: "i-tabler-eye-off", - file: "i-tabler-file", - folder: "i-tabler-folder", - folderOpen: "i-tabler-folder-open", - hash: "i-tabler-hash", - info: "i-tabler-info-square-rounded", - light: "i-tabler-sun", - loading: "i-tabler-loader-2", - menu: "i-tabler-menu", - minus: "i-tabler-minus", - panelClose: "i-tabler-layout-sidebar-left-collapse", - panelOpen: "i-tabler-layout-sidebar-left-expand", - plus: "i-tabler-plus", - reload: "i-tabler-reload", - search: "i-tabler-search", - stop: "i-tabler-player-stop", - success: "i-tabler-square-rounded-check", - system: "i-tabler-device-desktop", - tip: "i-tabler-bulb", - upload: "i-tabler-upload", - warning: "i-tabler-alert-triangle", - }, - }, -}); diff --git a/apps/frontend/app/components/OgImage/BasicTemplate.takumi.vue b/apps/frontend/app/components/OgImage/BasicTemplate.takumi.vue deleted file mode 100644 index 14daeee..0000000 --- a/apps/frontend/app/components/OgImage/BasicTemplate.takumi.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/apps/frontend/app/components/QrCodeForm.vue b/apps/frontend/app/components/QrCodeForm.vue deleted file mode 100644 index ca156df..0000000 --- a/apps/frontend/app/components/QrCodeForm.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - diff --git a/apps/frontend/app/components/ShortenUrlForm.vue b/apps/frontend/app/components/ShortenUrlForm.vue deleted file mode 100644 index 56b9a2e..0000000 --- a/apps/frontend/app/components/ShortenUrlForm.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - diff --git a/apps/frontend/app/composables/useQrCodeForm.ts b/apps/frontend/app/composables/useQrCodeForm.ts deleted file mode 100644 index 6eee815..0000000 --- a/apps/frontend/app/composables/useQrCodeForm.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { useRegle } from "@regle/core"; -import { required, regex } from "@regle/rules"; - -type Form = { - url: string; -}; - -export default function () { - const formData = ref
({ - url: "", - }); - - const rules = { - url: { - required, - regex: regex( - /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)$/, - ), - }, - }; - - return useRegle(formData, rules); -} diff --git a/apps/frontend/app/composables/useShortenForm.ts b/apps/frontend/app/composables/useShortenForm.ts deleted file mode 100644 index 978d0ea..0000000 --- a/apps/frontend/app/composables/useShortenForm.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { useRegle } from "@regle/core"; -import { regex, minLength, minValue, oneOf, required, maxLength } from "@regle/rules"; - -type Form = { - longUrl: string; - alias?: string; - neverExpire: boolean; - expireTime: 30; - expireUnit: ExpireUnit; -}; - -export default function () { - const formData = ref({ - longUrl: "", - alias: "", - neverExpire: true, - expireTime: 30, - expireUnit: "second", - }); - - const rules = { - longUrl: { - required, - regex: regex( - /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)$/, - ), - }, - alias: { - minLength: minLength(7), - maxLength: maxLength(255), - regex: regex(/^[a-zA-Z0-9_-]*$/), - }, - expireTime: { required, minValue: minValue(0, { allowEqual: false }) }, - expireUnit: { required, oneOf: oneOf(expireUnits) }, - }; - - return useRegle(formData, rules); -} diff --git a/apps/frontend/app/pages/index.vue b/apps/frontend/app/pages/index.vue deleted file mode 100644 index eba48ac..0000000 --- a/apps/frontend/app/pages/index.vue +++ /dev/null @@ -1,76 +0,0 @@ - - - diff --git a/apps/frontend/app/pages/qr.vue b/apps/frontend/app/pages/qr.vue deleted file mode 100644 index 0913ac4..0000000 --- a/apps/frontend/app/pages/qr.vue +++ /dev/null @@ -1,31 +0,0 @@ - - - diff --git a/apps/frontend/nuxt.config.ts b/apps/frontend/nuxt.config.ts index 2ddfdf3..062d436 100644 --- a/apps/frontend/nuxt.config.ts +++ b/apps/frontend/nuxt.config.ts @@ -1,37 +1,23 @@ export default defineNuxtConfig({ - modules: [ - "@nuxt/ui", - "@nuxt/fonts", - "@regle/nuxt", - "@vueuse/nuxt", - "@nuxt/image", - "@nuxt/test-utils/module", - "nuxt-og-image", - "@nuxtjs/robots", - "@nuxtjs/sitemap", - "nuxt-seo-utils", + modules: ["@nuxt/ui", "@vueuse/nuxt", "@nuxt/image", "@nuxtjs/seo"], + css: ["~/assets/css/main.css"], + srcDir: "src/app", + dir: { + public: "src/public", + }, + components: [ + { + path: "~/components", + pathPrefix: false, + }, ], - compatibilityDate: "2025-07-15", - devtools: { enabled: true }, - css: ["~/assets/css/global.css"], + // Runtime runtimeConfig: { public: { - siteUrl: "", apiBaseUrl: "", - preview: true, - }, - }, - app: { - head: { - titleTemplate: "%s %separator %siteName", - templateParams: { - separator: "|", - siteName: "Solitar", - }, - title: "Solitar", - meta: [{ name: "description", content: "A minimal URL shortener and QR generator" }], }, }, + // Deploy nitro: { prerender: { autoSubfolderIndex: false, @@ -41,34 +27,12 @@ export default defineNuxtConfig({ nodeCompat: true, }, }, - fonts: { - families: [ - { - name: "Geist", - provider: "google", - global: true, - }, - ], - }, - ui: { - fonts: false, - }, - site: { - name: "Solitar", - }, + // SEO robots: { blockAiBots: true, blockNonSeoBots: true, }, - ogImage: { - buildCache: true, - compatibility: { - runtime: { - takumi: "wasm", - }, - }, - }, - seo: { - fallbackTitle: false, - }, + // Development + compatibilityDate: "2025-07-15", + devtools: { enabled: true }, }); diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 69df981..2b29eb5 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -9,41 +9,30 @@ "preview": "nuxt preview", "postinstall": "nuxt prepare", "lint": "oxlint --type-aware --type-check", - "lint:fix": "oxlint --fix", - "test": "vitest run" + "lint:fix": "oxlint --fix" }, "dependencies": { - "@nuxt/fonts": "^0.14.0", - "@nuxt/image": "2.0.0", + "@nuxt/image": "^2.0.0", "@nuxt/ui": "^4.4.0", - "@nuxtjs/robots": "^5.7.0", - "@nuxtjs/sitemap": "^7.6.0", - "@regle/core": "^1.18.3", - "@regle/nuxt": "^1.18.3", - "@regle/rules": "^1.18.3", - "@vueuse/core": "^14.2.1", + "@nuxtjs/seo": "^3.4.0", "@vueuse/integrations": "^14.2.1", - "@vueuse/nuxt": "^14.2.1", "dayjs": "^1.11.19", "nuxt": "^4.3.1", - "nuxt-seo-utils": "^7.0.19", "qrcode": "^1.5.4", - "tailwindcss": "^4.1.18", + "tailwindcss": "^4.2.0", "ufo": "^1.6.3", + "valibot": "^1.2.0", "vue": "^3.5.28", "vue-router": "^4.6.4" }, "devDependencies": { - "@nuxt/test-utils": "^4.0.0", - "@takumi-rs/core": "^0.68.8", - "@takumi-rs/wasm": "^0.68.8", - "@vue/test-utils": "^2.4.6", - "happy-dom": "^20.6.1", - "nuxt-og-image": "6.0.0-beta.34", - "oxlint": "^1.43.0", - "oxlint-tsgolint": "^0.11.5", - "playwright-core": "^1.58.2", - "vitest": "^4.0.18", - "wrangler": "^4.65.0" + "@iconify-json/carbon": "^1.2.18", + "@iconify-json/lucide": "^1.2.92", + "@iconify-json/tabler": "^1.2.26", + "@vueuse/core": "^14.2.1", + "@vueuse/nuxt": "^14.2.1", + "oxlint": "^1.48.0", + "oxlint-tsgolint": "^0.14.2", + "wrangler": "^4.67.0" } } diff --git a/apps/frontend/src/app/app.config.ts b/apps/frontend/src/app/app.config.ts new file mode 100644 index 0000000..4c0bd42 --- /dev/null +++ b/apps/frontend/src/app/app.config.ts @@ -0,0 +1,7 @@ +export default defineAppConfig({ + ui: { + colors: { + primary: "indigo", + }, + }, +}); diff --git a/apps/frontend/app/app.vue b/apps/frontend/src/app/app.vue similarity index 77% rename from apps/frontend/app/app.vue rename to apps/frontend/src/app/app.vue index cb26b11..93d35ed 100644 --- a/apps/frontend/app/app.vue +++ b/apps/frontend/src/app/app.vue @@ -3,14 +3,14 @@ import type { ToasterProps } from "@nuxt/ui"; const toaster: ToasterProps = { position: "top-right" }; -const config = useRuntimeConfig(); +const siteConfig = useSiteConfig();