cinqcinqdev-seo 0.1.5 → 0.1.7
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/dist/module.d.mts +62 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +99 -14
- package/dist/runtime/assets/admin-tw.css +1 -0
- package/dist/runtime/assets/admin-tw.input.css +1 -0
- package/dist/runtime/assets/admin.css +3 -0
- package/dist/runtime/components/admin/DynamicRenderer.d.vue.ts +3 -0
- package/dist/runtime/components/admin/DynamicRenderer.vue +30 -0
- package/dist/runtime/components/admin/DynamicRenderer.vue.d.ts +3 -0
- package/dist/runtime/components/admin/Navbar.d.vue.ts +3 -0
- package/dist/runtime/components/admin/Navbar.vue +80 -0
- package/dist/runtime/components/admin/Navbar.vue.d.ts +3 -0
- package/dist/runtime/composables/useAdminSections.d.ts +11 -0
- package/dist/runtime/composables/useAdminSections.js +332 -0
- package/dist/runtime/middleware/admin-auth.d.ts +2 -0
- package/dist/runtime/middleware/admin-auth.js +11 -0
- package/dist/runtime/pages/admin/account.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/account.vue +154 -0
- package/dist/runtime/pages/admin/account.vue.d.ts +3 -0
- package/dist/runtime/pages/admin/editor/[id].d.vue.ts +3 -0
- package/dist/runtime/pages/admin/editor/[id].vue +521 -0
- package/dist/runtime/pages/admin/editor/[id].vue.d.ts +3 -0
- package/dist/runtime/pages/admin/index.d.vue.ts +3 -0
- package/dist/runtime/pages/admin/index.vue +40 -0
- package/dist/runtime/pages/admin/index.vue.d.ts +3 -0
- package/dist/runtime/pages/admin/pages/[type].d.vue.ts +3 -0
- package/dist/runtime/pages/admin/pages/[type].vue +137 -0
- package/dist/runtime/pages/admin/pages/[type].vue.d.ts +3 -0
- package/dist/runtime/plugins/admin-font.client.d.ts +7 -0
- package/dist/runtime/plugins/admin-font.client.js +6 -0
- package/dist/runtime/stores/adminUser.d.ts +1 -0
- package/dist/runtime/stores/adminUser.js +55 -0
- package/dist/types.d.mts +2 -12
- package/package.json +2 -2
- package/dist/module.d.cts +0 -2
package/dist/module.d.mts
CHANGED
|
@@ -1,2 +1,62 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
|
|
3
|
+
interface PageTypeConfig {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
icon?: string;
|
|
7
|
+
}
|
|
8
|
+
interface PlanConfig {
|
|
9
|
+
value: string;
|
|
10
|
+
title: string;
|
|
11
|
+
subtitle?: string;
|
|
12
|
+
price: string;
|
|
13
|
+
features?: string[];
|
|
14
|
+
popular?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface SectionFieldConfig {
|
|
17
|
+
type: 'text' | 'textarea' | 'color' | 'image' | 'boolean' | 'select' | 'cards';
|
|
18
|
+
label: string;
|
|
19
|
+
options?: Array<{
|
|
20
|
+
value: string;
|
|
21
|
+
label: string;
|
|
22
|
+
icon?: string;
|
|
23
|
+
}>;
|
|
24
|
+
i18n?: boolean;
|
|
25
|
+
group?: string;
|
|
26
|
+
}
|
|
27
|
+
interface SectionConfig {
|
|
28
|
+
label: string;
|
|
29
|
+
icon?: string;
|
|
30
|
+
defaultProps: Record<string, any>;
|
|
31
|
+
fields: Record<string, SectionFieldConfig>;
|
|
32
|
+
}
|
|
33
|
+
interface ModuleOptions {
|
|
34
|
+
/** Branding shown in the admin navbar */
|
|
35
|
+
branding?: {
|
|
36
|
+
name?: string;
|
|
37
|
+
logoUrl?: string;
|
|
38
|
+
};
|
|
39
|
+
/** Page type cards shown on the dashboard */
|
|
40
|
+
pageTypes?: PageTypeConfig[];
|
|
41
|
+
/** Plans shown on the account page */
|
|
42
|
+
plans?: PlanConfig[];
|
|
43
|
+
/** Route to redirect to when not authenticated */
|
|
44
|
+
loginRoute?: string;
|
|
45
|
+
/** Supabase table names */
|
|
46
|
+
tables?: {
|
|
47
|
+
pages?: string;
|
|
48
|
+
users?: string;
|
|
49
|
+
};
|
|
50
|
+
/** Supabase storage bucket for file uploads */
|
|
51
|
+
storageBucket?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Extra section definitions merged with the module defaults.
|
|
54
|
+
* Keys must match component names in components/sections/ of the consuming app.
|
|
55
|
+
* e.g. { MyCustomSection: { label: 'Custom', icon: '✨', defaultProps: {}, fields: {} } }
|
|
56
|
+
*/
|
|
57
|
+
extraSections?: Record<string, SectionConfig>;
|
|
58
|
+
}
|
|
59
|
+
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
60
|
+
|
|
61
|
+
export { _default as default };
|
|
62
|
+
export type { ModuleOptions, PageTypeConfig, PlanConfig, SectionConfig, SectionFieldConfig };
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,18 +1,103 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineNuxtModule, createResolver, addPlugin, addComponentsDir, addImportsDir, addRouteMiddleware } from '@nuxt/kit';
|
|
2
|
+
import { defu } from 'defu';
|
|
3
|
+
import { join } from 'node:path';
|
|
2
4
|
|
|
3
|
-
const
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
5
|
+
const defaultPageTypes = [
|
|
6
|
+
{ id: "landing_page", label: "Landing Page", icon: "\u{1F680}" },
|
|
7
|
+
{ id: "service_page", label: "Service Page", icon: "\u{1F6E0}\uFE0F" },
|
|
8
|
+
{ id: "about_page", label: "About Page", icon: "\u{1F44B}" },
|
|
9
|
+
{ id: "product_page", label: "Product Page", icon: "\u{1F4E6}" },
|
|
10
|
+
{ id: "blog_article", label: "Blog Article", icon: "\u{1F4DD}" },
|
|
11
|
+
{ id: "portfolio_item", label: "Portfolio Item", icon: "\u{1F3A8}" }
|
|
12
|
+
];
|
|
13
|
+
const module$1 = defineNuxtModule({
|
|
14
|
+
meta: {
|
|
15
|
+
name: "cinqcinqdev-seo",
|
|
16
|
+
configKey: "adminCms",
|
|
17
|
+
compatibility: { nuxt: "^3.0.0" }
|
|
7
18
|
},
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
defaults: {
|
|
20
|
+
branding: { name: "Admin CMS", logoUrl: "" },
|
|
21
|
+
pageTypes: [],
|
|
22
|
+
plans: [],
|
|
23
|
+
loginRoute: "/login",
|
|
24
|
+
tables: { pages: "pages", users: "users" },
|
|
25
|
+
storageBucket: "site",
|
|
26
|
+
extraSections: {}
|
|
27
|
+
},
|
|
28
|
+
setup(options, nuxt) {
|
|
29
|
+
const { resolve } = createResolver(import.meta.url);
|
|
30
|
+
const resolvedOptions = {
|
|
31
|
+
...defu(options, {
|
|
32
|
+
branding: { name: "Admin CMS", logoUrl: "" },
|
|
33
|
+
plans: [],
|
|
34
|
+
loginRoute: "/login",
|
|
35
|
+
tables: { pages: "pages", users: "users" },
|
|
36
|
+
storageBucket: "site",
|
|
37
|
+
extraSections: {}
|
|
38
|
+
}),
|
|
39
|
+
pageTypes: options.pageTypes?.length ? options.pageTypes : defaultPageTypes,
|
|
40
|
+
plans: options.plans?.length ? options.plans : []
|
|
41
|
+
};
|
|
42
|
+
nuxt.options.runtimeConfig.public.adminCms = resolvedOptions;
|
|
43
|
+
nuxt.options.css.push(resolve("./runtime/assets/admin-tw.css"));
|
|
44
|
+
nuxt.options.css.push(resolve("./runtime/assets/admin.css"));
|
|
45
|
+
addPlugin(resolve("./runtime/plugins/admin-font.client"));
|
|
46
|
+
nuxt.hook("tailwindcss:config", (tailwindConfig) => {
|
|
47
|
+
const adminPath = resolve("./runtime/**/*.{vue,ts}");
|
|
48
|
+
if (Array.isArray(tailwindConfig.content)) {
|
|
49
|
+
tailwindConfig.content.push(adminPath);
|
|
50
|
+
} else {
|
|
51
|
+
tailwindConfig.content ??= {};
|
|
52
|
+
tailwindConfig.content.files ??= [];
|
|
53
|
+
tailwindConfig.content.files.push(adminPath);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
addComponentsDir({
|
|
57
|
+
path: resolve("./runtime/components"),
|
|
58
|
+
global: true
|
|
59
|
+
});
|
|
60
|
+
addImportsDir(resolve("./runtime/stores"));
|
|
61
|
+
addImportsDir(resolve("./runtime/composables"));
|
|
62
|
+
nuxt.hook("components:dirs", (dirs) => {
|
|
63
|
+
const sectionsPath = join(nuxt.options.rootDir, "components", "sections");
|
|
64
|
+
const existing = dirs.find((d) => typeof d === "object" && d.path === sectionsPath);
|
|
65
|
+
if (existing) {
|
|
66
|
+
existing.global = true;
|
|
67
|
+
} else {
|
|
68
|
+
dirs.push({ path: sectionsPath, global: true });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
nuxt.hook("pages:extend", (pages) => {
|
|
72
|
+
pages.push(
|
|
73
|
+
{
|
|
74
|
+
name: "admin",
|
|
75
|
+
path: "/admin",
|
|
76
|
+
file: resolve("./runtime/pages/admin/index.vue")
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: "admin-account",
|
|
80
|
+
path: "/admin/account",
|
|
81
|
+
file: resolve("./runtime/pages/admin/account.vue")
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "admin-pages-type",
|
|
85
|
+
path: "/admin/pages/:type",
|
|
86
|
+
file: resolve("./runtime/pages/admin/pages/[type].vue")
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "admin-editor-id",
|
|
90
|
+
path: "/admin/editor/:id",
|
|
91
|
+
file: resolve("./runtime/pages/admin/editor/[id].vue")
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
addRouteMiddleware({
|
|
96
|
+
name: "admin-auth",
|
|
97
|
+
path: resolve("./runtime/middleware/admin-auth"),
|
|
98
|
+
global: true
|
|
99
|
+
});
|
|
12
100
|
}
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
/** @type {import("/Users/mac/Desktop/nuxt-admin-cms/src/module")} */
|
|
16
|
-
const _module = await jiti.import("/Users/mac/Desktop/nuxt-admin-cms/src/module.ts");
|
|
101
|
+
});
|
|
17
102
|
|
|
18
|
-
export
|
|
103
|
+
export { module$1 as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.pointer-events-none{pointer-events:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.-right-2{right:-.5rem}.-top-2{top:-.5rem}.left-0{left:0}.top-0{top:0}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.z-\[100\]{z-index:100}.z-\[60\]{z-index:60}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.block{display:block}.flex{display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-1\.5{height:.375rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2{height:.5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-5{height:1.25rem}.h-8{height:2rem}.h-full{height:100%}.h-screen{height:100vh}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-0{width:0}.w-1\.5{width:.375rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-5{width:1.25rem}.w-64{width:16rem}.w-8{width:2rem}.w-80{width:20rem}.w-auto{width:auto}.w-full{width:100%}.min-w-0{min-width:0}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-md{max-width:28rem}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.75rem*var(--tw-space-y-reverse));margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.5rem*var(--tw-space-y-reverse));margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity,1))}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[24px\]{border-radius:24px}.rounded-\[32px\]{border-radius:32px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-black{--tw-border-opacity:1;border-color:rgb(0 0 0/var(--tw-border-opacity,1))}.border-black\/5{border-color:rgba(0,0,0,.05)}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.border-current{border-color:currentColor}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.border-green-100{--tw-border-opacity:1;border-color:rgb(220 252 231/var(--tw-border-opacity,1))}.border-green-200{--tw-border-opacity:1;border-color:rgb(187 247 208/var(--tw-border-opacity,1))}.border-green-500{--tw-border-opacity:1;border-color:rgb(34 197 94/var(--tw-border-opacity,1))}.border-red-100{--tw-border-opacity:1;border-color:rgb(254 226 226/var(--tw-border-opacity,1))}.border-white\/10{border-color:hsla(0,0%,100%,.1)}.bg-\[\#EBEBEF\]{--tw-bg-opacity:1;background-color:rgb(235 235 239/var(--tw-bg-opacity,1))}.bg-\[\#F5F5F7\]{--tw-bg-opacity:1;background-color:rgb(245 245 247/var(--tw-bg-opacity,1))}.bg-amber-500{--tw-bg-opacity:1;background-color:rgb(245 158 11/var(--tw-bg-opacity,1))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-black\/5{background-color:rgba(0,0,0,.05)}.bg-black\/50{background-color:rgba(0,0,0,.5)}.bg-black\/90{background-color:rgba(0,0,0,.9)}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-blue-50\/50{background-color:rgba(239,246,255,.5)}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-300{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity,1))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-gray-50\/50{background-color:rgba(249,250,251,.5)}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(220 252 231/var(--tw-bg-opacity,1))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity,1))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity,1))}.bg-orange-500{--tw-bg-opacity:1;background-color:rgb(249 115 22/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/10{background-color:hsla(0,0%,100%,.1)}.bg-white\/80{background-color:hsla(0,0%,100%,.8)}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-blue-600{--tw-gradient-from:#2563eb var(--tw-gradient-from-position);--tw-gradient-to:rgba(37,99,235,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.to-violet-600{--tw-gradient-to:#7c3aed var(--tw-gradient-to-position)}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-10{padding:2.5rem}.p-2{padding:.5rem}.p-20{padding:5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-bottom:.125rem;padding-top:.125rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-2\.5{padding-bottom:.625rem;padding-top:.625rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-4{padding-bottom:1rem;padding-top:1rem}.py-5{padding-bottom:1.25rem;padding-top:1.25rem}.py-8{padding-bottom:2rem;padding-top:2rem}.pb-4{padding-bottom:1rem}.pb-40{padding-bottom:10rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[10px\]{font-size:10px}.text-\[7px\]{font-size:7px}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-amber-500{--tw-text-opacity:1;color:rgb(245 158 11/var(--tw-text-opacity,1))}.text-amber-600{--tw-text-opacity:1;color:rgb(217 119 6/var(--tw-text-opacity,1))}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity,1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity,1))}.text-green-700{--tw-text-opacity:1;color:rgb(21 128 61/var(--tw-text-opacity,1))}.text-red-400{--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity,1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/70{color:hsla(0,0%,100%,.7)}.text-white\/80{color:hsla(0,0%,100%,.8)}.opacity-0{opacity:0}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-2{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-2,.ring-4{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-4{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-inset{--tw-ring-inset:inset}.ring-blue-500{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.blur{--tw-blur:blur(8px)}.blur,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px)}.backdrop-blur-md,.backdrop-blur-sm{backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px)}.backdrop-blur-xl{--tw-backdrop-blur:blur(24px);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-opacity{transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-shadow{transition-duration:.15s;transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-300{transition-duration:.3s}.hover\:border-black:hover{--tw-border-opacity:1;border-color:rgb(0 0 0/var(--tw-border-opacity,1))}.hover\:border-blue-300:hover{--tw-border-opacity:1;border-color:rgb(147 197 253/var(--tw-border-opacity,1))}.hover\:border-blue-400:hover{--tw-border-opacity:1;border-color:rgb(96 165 250/var(--tw-border-opacity,1))}.hover\:border-blue-500:hover{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.hover\:border-gray-300:hover{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.hover\:bg-black:hover{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.hover\:bg-blue-50\/50:hover{background-color:rgba(239,246,255,.5)}.hover\:bg-blue-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity,1))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.hover\:bg-gray-800:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}.hover\:bg-white\/10:hover{background-color:hsla(0,0%,100%,.1)}.hover\:bg-white\/20:hover{background-color:hsla(0,0%,100%,.2)}.hover\:text-black:hover{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.hover\:text-blue-500:hover{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.hover\:text-blue-600:hover{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.hover\:text-red-600:hover{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.focus\:border-black:focus{--tw-border-opacity:1;border-color:rgb(0 0 0/var(--tw-border-opacity,1))}.focus\:ring-1:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-1:focus,.focus\:ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-black:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(0 0 0/var(--tw-ring-opacity,1))}.active\:scale-95:active{--tw-scale-x:.95;--tw-scale-y:.95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.group:hover .group-hover\:text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.group:hover .group-hover\:opacity-100{opacity:1}@media (min-width:640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}}@media (min-width:768px){.md\:flex{display:flex}.md\:hidden{display:none}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:p-10{padding:2.5rem}}@media (min-width:1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@tailwind components;@tailwind utilities;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap");[data-admin-cms]{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}[data-admin-cms] :not([data-admin-preview] *){box-sizing:border-box}[data-admin-preview],[data-admin-preview] *{font-family:var(
|
|
2
|
+
--admin-site-font,var(--font-body,var(--font-sans,var(--font-family,inherit)))
|
|
3
|
+
)}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
content: { type: Array, required: true },
|
|
4
|
+
selectedId: { type: [Number, null], required: true }
|
|
5
|
+
});
|
|
6
|
+
const emit = defineEmits(["select"]);
|
|
7
|
+
const resolveSection = (type) => resolveComponent(`Sections${type}`);
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div class="w-full min-h-full bg-white pb-40">
|
|
12
|
+
<div
|
|
13
|
+
v-for="(block, index) in content"
|
|
14
|
+
:key="index"
|
|
15
|
+
@click.stop="emit('select', index)"
|
|
16
|
+
class="relative group cursor-pointer"
|
|
17
|
+
:class="{ 'ring-2 ring-blue-500 ring-inset': selectedId === index }"
|
|
18
|
+
>
|
|
19
|
+
<div class="absolute inset-0 bg-black/5 opacity-0 group-hover:opacity-100 transition-opacity z-10 pointer-events-none" />
|
|
20
|
+
<div v-if="selectedId === index" class="absolute top-0 left-0 bg-blue-500 text-white text-[10px] px-2 py-1 z-20 font-bold uppercase">
|
|
21
|
+
{{ block.type }}
|
|
22
|
+
</div>
|
|
23
|
+
<component :is="resolveSection(block.type)" v-bind="block.props" />
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div v-if="content.length === 0" class="p-20 text-center text-gray-300 italic text-sm">
|
|
27
|
+
Your page is empty. Add a section to get started.
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<nav data-admin-cms class="sticky top-0 z-50 bg-black shadow-md">
|
|
3
|
+
<div class="px-4 sm:px-6 lg:px-8">
|
|
4
|
+
<div class="flex justify-between h-16">
|
|
5
|
+
<!-- Brand -->
|
|
6
|
+
<div class="flex-shrink-0 flex items-center">
|
|
7
|
+
<NuxtLink to="/admin" class="flex items-center gap-2">
|
|
8
|
+
<img v-if="branding.logoUrl" :src="branding.logoUrl" class="h-8 w-auto" :alt="branding.name" />
|
|
9
|
+
<span v-else class="w-8 h-8 bg-blue-500 rounded-md flex items-center justify-center text-white font-bold text-xs">
|
|
10
|
+
{{ branding.name?.substring(0, 2)?.toUpperCase() || "A" }}
|
|
11
|
+
</span>
|
|
12
|
+
<span class="text-lg font-bold tracking-wide text-white">{{ branding.name }}</span>
|
|
13
|
+
</NuxtLink>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<!-- Desktop nav -->
|
|
17
|
+
<div class="hidden md:flex items-center gap-6">
|
|
18
|
+
<NuxtLink v-if="user" to="/admin" class="text-sm text-white/70 hover:text-white transition-colors">
|
|
19
|
+
Dashboard
|
|
20
|
+
</NuxtLink>
|
|
21
|
+
<NuxtLink v-if="user" to="/admin/account" class="text-sm text-white/70 hover:text-white transition-colors">
|
|
22
|
+
Account
|
|
23
|
+
</NuxtLink>
|
|
24
|
+
<button
|
|
25
|
+
v-if="user"
|
|
26
|
+
@click="handleSignOut"
|
|
27
|
+
:disabled="userStore.loading"
|
|
28
|
+
class="text-sm px-4 py-2 bg-white/10 hover:bg-white/20 text-white rounded-lg transition-colors"
|
|
29
|
+
>
|
|
30
|
+
{{ userStore.loading ? "..." : "Sign out" }}
|
|
31
|
+
</button>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<!-- Mobile toggle -->
|
|
35
|
+
<div class="flex items-center md:hidden">
|
|
36
|
+
<button @click="menuOpen = !menuOpen" class="p-2 text-white/70 hover:text-white">
|
|
37
|
+
<svg v-if="!menuOpen" class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
38
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
|
|
39
|
+
</svg>
|
|
40
|
+
<svg v-else class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
41
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
42
|
+
</svg>
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<!-- Mobile menu -->
|
|
49
|
+
<div v-if="menuOpen" class="md:hidden bg-gray-900 border-t border-white/10">
|
|
50
|
+
<div class="flex flex-col gap-1 p-4">
|
|
51
|
+
<NuxtLink to="/admin" @click="menuOpen = false" class="px-3 py-2 text-white/80 hover:text-white rounded-md hover:bg-white/10 transition-colors">
|
|
52
|
+
Dashboard
|
|
53
|
+
</NuxtLink>
|
|
54
|
+
<NuxtLink to="/admin/account" @click="menuOpen = false" class="px-3 py-2 text-white/80 hover:text-white rounded-md hover:bg-white/10 transition-colors">
|
|
55
|
+
Account
|
|
56
|
+
</NuxtLink>
|
|
57
|
+
<button v-if="user" @click="handleSignOut" class="text-left px-3 py-2 text-white/80 hover:text-white rounded-md hover:bg-white/10 transition-colors">
|
|
58
|
+
Sign out
|
|
59
|
+
</button>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</nav>
|
|
63
|
+
</template>
|
|
64
|
+
|
|
65
|
+
<script setup>
|
|
66
|
+
import { useAdminUserStore } from "../../../stores/adminUser";
|
|
67
|
+
const config = useRuntimeConfig().public.adminCms;
|
|
68
|
+
const branding = computed(() => ({
|
|
69
|
+
name: config?.branding?.name || "Admin",
|
|
70
|
+
logoUrl: config?.branding?.logoUrl || ""
|
|
71
|
+
}));
|
|
72
|
+
const user = useSupabaseUser();
|
|
73
|
+
const userStore = useAdminUserStore();
|
|
74
|
+
const router = useRouter();
|
|
75
|
+
const menuOpen = ref(false);
|
|
76
|
+
const handleSignOut = async () => {
|
|
77
|
+
await userStore.signOut();
|
|
78
|
+
router.push(useRuntimeConfig().public.adminCms?.loginRoute || "/login");
|
|
79
|
+
};
|
|
80
|
+
</script>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default section definitions for the visual editor.
|
|
3
|
+
* Keys must match component names in the consuming app's components/sections/ directory.
|
|
4
|
+
* e.g. HeroSection → components/sections/HeroSection.vue → <SectionsHeroSection />
|
|
5
|
+
*
|
|
6
|
+
* Add your own sections via the `extraSections` module option in nuxt.config.ts.
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_SECTIONS: Record<string, any>;
|
|
9
|
+
export declare const useAdminSections: () => {
|
|
10
|
+
[x: string]: any;
|
|
11
|
+
};
|