More things
All checks were successful
Build and Deploy Nuxt / build (push) Successful in 1m46s

This commit is contained in:
2026-09-21 23:02:37 +02:00
parent 2b29d55688
commit 42084aeeb4
16 changed files with 1324 additions and 274 deletions

View File

@@ -6,7 +6,7 @@ Monorepo for aranroig.com — a personal portfolio website with blog, art galler
- **Frontend**: Nuxt 4 + Vue 3 + TypeScript + SCSS
- **Backend**: Express 5 + Mongoose (MongoDB)
- **i18n**: @nuxtjs/i18n (English, Spanish, Catalan)
- **i18n**: @nuxtjs/i18n (English, Spanish, Catalan, Chinese)
- **Content**: Nuxt Content v3 with Zod-sourced Markdown collections
- **Image optimization**: @nuxt/image
- **Build**: Vite
@@ -27,15 +27,15 @@ Monorepo for aranroig.com — a personal portfolio website with blog, art galler
│ │ │ ├── layouts/ # Page layout wrappers
│ │ │ ├── parts/ # Header, footer, navigation pieces
│ │ │ └── content/ # Blog, art content components
│ │ ├── composables/ # useApi(), theme.ts (light/dark + accent colors)
│ │ ├── composables/ # useApi(), useAuth(), theme.ts (light/dark + accent colors)
│ │ ├── i18n.config.ts# VueI18n fallback locale setup
│ │ └── pages/ # File-based routing (index, blog, art, contact)
│ │ └── pages/ # File-based routing (index, blog, art, contact, admin)
│ ├── content/ # Markdown collections organized by locale
│ │ ├── fixed/ # Static pages per locale
│ │ ├── blog/ # Blog posts
│ │ ├── art/ # Art pieces
│ │ └── projects/ # Project cards
│ ├── i18n/locales/ # en.json, es.json, ca.json translation files
│ ├── i18n/locales/ # en.json, es.json, ca.json, zh.json translation files
│ ├── content.config.ts # Content collection schemas (Zod)
│ └── nuxt.config.ts # Nuxt config: modules, i18n, runtime config
├── docker-compose.yml # Services: nginx, frontend, backend
@@ -75,6 +75,7 @@ In `backend/`:
- Backend reads `.env.development` or `.env.production` based on `NODE_ENV`. Requires `DB_URI` for MongoDB.
- Frontend runtime config key `public.apiBaseUrl` sets the backend API URL used by `useApi()`.
- Content lives in `frontend/content/` under collection folders (`blog`, `fixed`, `art`, `projects`), each with locale subdirectories (`en`, `es`, `ca`).
- Admin panel lives at `/admin` (login, dashboard, orders), guarded by the `admin-auth` middleware and the `admin_token` cookie. Admin pages share the `AdminLayout` shell with the `AdminSidebar`.
## Code Style
@@ -84,6 +85,8 @@ In `backend/`:
- File names: kebab-case for components and pages.
- CSS variables driven by SCSS maps define themes (light/dark) and accent colors.
- TUI aesthetic: box-drawing characters, monospace font (**Hermit** / "Hurmit" via Nerd Fonts), `steps()` easing transitions, pixel-art SVG elements.
- Headings and buttons carry no `>` prompt prefix.
- Titles use proper capitalization: sentence case with capitalized proper nouns (e.g. "Admin dashboard", "Hibolia orders"), never ALL CAPS.
## Content Collections

View File

@@ -20,7 +20,7 @@
<style lang="scss" scoped>
.tui-frame {
position: relative;
margin: 15px;
margin: var(--container-margin, 15px);
background: var(--color-background-fore);
box-shadow: 4px -4px 0px 0px var(--color-container-shadow);
}

View File

@@ -16,6 +16,7 @@
flex-direction: column;
justify-content: center;
margin-top: 60px;
margin-bottom: 60px;
}
span {

View File

@@ -0,0 +1,40 @@
<script setup lang="ts">
import AdminSidebar from '~/components/parts/AdminSidebar.vue';
</script>
<template>
<div class="admin-shell">
<AdminSidebar />
<main class="admin-main">
<slot />
</main>
</div>
</template>
<style lang="scss" scoped>
.admin-shell {
position: fixed;
inset: 0;
z-index: 1000;
display: flex;
background: var(--color-background);
}
.admin-main {
flex: 1;
min-width: 0;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.admin-main :slotted(*) {
flex: 1;
}
@media screen and (max-width: 900px) {
.admin-shell {
flex-direction: column;
}
}
</style>

View File

@@ -0,0 +1,225 @@
<script setup lang="ts">
const auth = useAuth()
const route = useRoute()
const localePath = useLocalePath()
const orderCount = useState<number | null>('admin-order-count', () => null)
const navItems = [
{ key: 'dashboard', to: '/admin', label: 'admin.sidebar.nav_dashboard' },
{ key: 'orders', to: '/admin/orders', label: 'admin.sidebar.nav_orders' }
]
const isActive = (key: string) =>
key === 'dashboard'
? route.path === '/admin' || route.path === '/admin/'
: route.path.startsWith('/admin/orders')
const onLogout = () => {
auth.logout()
navigateTo('/admin/login')
}
</script>
<template>
<aside class="admin-sidebar">
<div class="sidebar-head">
<span class="sidebar-title">{{ $t('admin.sidebar.title') }}</span>
</div>
<span class="sidebar-rule" aria-hidden="true">══════════════════</span>
<nav class="sidebar-nav">
<NuxtLink
v-for="item in navItems"
:key="item.key"
:to="item.to"
class="nav-item"
:class="{ 'nav-item-active': isActive(item.key) }"
>
<span class="nav-sep" aria-hidden="true">{{ item.key === 'dashboard' ? '▸' : '├' }}</span>
<span class="nav-label">{{ $t(item.label) }}</span>
<span v-if="item.key === 'orders' && orderCount !== null" class="nav-badge">[{{ orderCount }}]</span>
</NuxtLink>
</nav>
<div class="sidebar-bottom">
<span class="sidebar-rule" aria-hidden="true">══════════════════</span>
<NuxtLink :to="localePath('index')" class="nav-item nav-item-site">
<span class="nav-sep" aria-hidden="true">←</span>
<span class="nav-label">{{ $t('admin.sidebar.back_site') }}</span>
</NuxtLink>
<button class="sidebar-logout" @click="onLogout">&gt;_ {{ $t('admin.dashboard.logout') }}</button>
</div>
</aside>
</template>
<style lang="scss" scoped>
.admin-sidebar {
display: flex;
flex-direction: column;
width: 220px;
flex-shrink: 0;
padding: 16px 12px;
background: var(--color-background-fore);
border-right: 1px solid var(--color-border-color);
box-shadow: inset -2px 0 0 0 var(--color-container-shadow);
}
.sidebar-head {
display: flex;
align-items: baseline;
gap: 8px;
padding: 0 6px 8px;
}
.sidebar-title {
font-family: 'Hurmit', monospace;
font-size: 1rem;
letter-spacing: 2px;
color: var(--color-text);
}
.sidebar-rule {
display: block;
font-family: 'Hurmit', monospace;
font-size: 8px;
line-height: 1;
color: var(--color-border-color);
white-space: nowrap;
overflow: hidden;
margin: 4px 0 12px;
}
.sidebar-nav {
display: flex;
flex-direction: column;
gap: 2px;
}
.nav-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 10px;
font-family: 'Hurmit', monospace;
font-size: 0.85rem;
color: var(--color-text);
text-decoration: none;
text-shadow: none;
border: 1px solid transparent;
transition: all 120ms steps(3);
.nav-sep {
color: var(--color-text);
opacity: 0.35;
font-size: 0.75rem;
}
&:hover {
background-color: var(--color-hover);
border-color: var(--color-border-color);
.nav-sep {
color: var(--color-link);
opacity: 1;
}
}
}
.nav-item-active {
color: var(--color-link);
border-color: var(--color-link);
.nav-sep,
.nav-badge {
color: var(--color-link);
opacity: 1;
}
}
.nav-badge {
margin-left: auto;
font-size: 0.72rem;
color: var(--color-link);
opacity: 0.7;
}
.sidebar-bottom {
margin-top: auto;
display: flex;
flex-direction: column;
gap: 2px;
}
.sidebar-logout {
font-family: 'Hurmit', monospace;
font-size: 0.85rem;
color: var(--color-text);
background: transparent;
border: 1px solid var(--color-border-color);
padding: 6px 14px;
margin-top: 8px;
cursor: pointer;
text-align: left;
transition: all 120ms steps(3);
&:hover {
color: var(--color-link);
border-color: var(--color-link);
}
}
@media screen and (max-width: 900px) {
.admin-sidebar {
width: 100%;
flex-direction: row;
align-items: center;
gap: 12px;
padding: 8px 12px;
border-right: none;
border-bottom: 1px solid var(--color-border-color);
box-shadow: inset 0 -2px 0 0 var(--color-container-shadow);
}
.sidebar-head {
padding: 0;
flex-shrink: 0;
}
.sidebar-rule {
display: none;
}
.sidebar-nav {
flex-direction: row;
flex-wrap: wrap;
gap: 4px;
}
.sidebar-bottom {
margin-top: 0;
margin-left: auto;
flex-direction: row;
align-items: center;
gap: 8px;
}
.sidebar-logout {
margin-top: 0;
white-space: nowrap;
}
}
@media screen and (max-width: 600px) {
.nav-item {
font-size: 0.75rem;
padding: 4px 8px;
}
.sidebar-logout {
font-size: 0.75rem;
padding: 4px 10px;
}
}
</style>

View File

@@ -89,6 +89,13 @@ onUnmounted(() => window.removeEventListener('scroll', onScroll));
transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.3s ease;
// Below 900px the full header is hidden, so keep the bar always shown.
@media screen and (max-width: 900px) {
transform: translateY(0);
opacity: 1;
pointer-events: auto;
}
&.visible {
transform: translateY(0);
opacity: 1;

View File

@@ -120,7 +120,7 @@ const preloadImages = (imageArray) => {
<style lang="scss" scoped>
.header {
position: relative;
margin-top: 30px;
margin-top: 42px;
user-select: none;
display: flex;
justify-content: space-between;
@@ -129,6 +129,10 @@ const preloadImages = (imageArray) => {
flex-direction: column;
gap: 8px;
}
@media screen and (max-width: 900px) {
display: none;
}
}
.header-container {
@@ -139,6 +143,12 @@ const preloadImages = (imageArray) => {
margin-top: 20px;
}
}
&.right {
:deep(.site-options) {
margin-top: 12px;
}
}
}
.undertable-wrapper {
@@ -153,16 +163,8 @@ const preloadImages = (imageArray) => {
margin-top: -340px;
}
@media screen and (max-width: 900px) and (min-width: 600px) {
margin-top: -240px;
}
@media screen and (max-width: 600px) {
margin-top: -300px;
}
@media screen and (max-width: 480px) {
margin-top: -340px;
@media screen and (max-width: 900px) {
display: none;
}
}

View File

@@ -1,4 +1,6 @@
<script setup lang="ts">
import AdminLayout from '~/components/layouts/AdminLayout.vue';
definePageMeta({ middleware: 'admin-auth' });
useHead({
@@ -10,34 +12,9 @@ const { getAuth } = useApi();
const auth = useAuth();
const stats = ref<any>(null);
const orders = ref<any[]>([]);
const loading = ref(true);
const errorMsg = ref('');
const COLOR_HEX: Record<string, string> = {
red: '#d64545',
gold: '#d4af37',
silver: '#c0c0c0',
orange: '#e0823c',
yellow: '#e2cf3c',
green: '#5fae4e',
blue: '#4c8be0',
purple: '#9b59d0',
black: '#1a1a1a',
white: '#f2f2f2',
pink: '#e88fb3',
turquoise: '#40c4b8',
teal: '#17857c',
navy: '#34549c',
lavender: '#b98fe0',
magenta: '#cf479f',
lime: '#a8d14e',
coral: '#ef8368'
};
const orderSwatch = (order: any) =>
order.color === 'custom' ? order.customColor : COLOR_HEX[order.color] || 'transparent';
const formatUptime = (seconds: number) => {
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
@@ -68,28 +45,15 @@ const loadStats = async () => {
}
};
const loadOrders = async () => {
try {
orders.value = await getAuth('/hibolia/orders');
} catch (e: any) {
if (e?.status === 401) {
redirectToLogin();
}
}
};
const formatDate = (value: string) => new Date(value).toLocaleString();
onMounted(async () => {
const me = await auth.fetchMe();
if (!me) {
redirectToLogin();
return;
}
await Promise.all([loadStats(), loadOrders()]);
await loadStats();
intervalId = setInterval(() => {
loadStats();
loadOrders();
}, 30000);
});
@@ -97,17 +61,12 @@ let intervalId: ReturnType<typeof setInterval> | null = null;
onBeforeUnmount(() => {
if (intervalId) clearInterval(intervalId);
});
const onLogout = () => redirectToLogin();
</script>
<template>
<div class="dash-screen">
<AdminLayout>
<Container class="dash-frame">
<div class="dash-top">
<h1 class="dash-title">&gt; {{ $t('admin.dashboard.title') }}</h1>
<button class="logout-btn" @click="onLogout">&gt;_ {{ $t('admin.dashboard.logout') }}</button>
</div>
<h1 class="dash-title">{{ $t('admin.dashboard.title') }}</h1>
<p v-if="auth.user.value" class="dash-welcome">
{{ $t('admin.dashboard.welcome') }} <span class="hl">{{ auth.user.value.username }}</span>
@@ -117,118 +76,54 @@ const onLogout = () => redirectToLogin();
<p v-if="loading" class="dash-loading blink">{{ $t('admin.dashboard.loading') }}</p>
<template v-if="stats && !loading">
<h2 class="dash-section">{{ $t('admin.dashboard.section_status') }}</h2>
<div class="stat-grid">
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.status') }}</span>
<span class="stat-value ok">{{ stats.status }}</span>
<section>
<h2 class="dash-section">{{ $t('admin.dashboard.section_status') }}</h2>
<div class="stat-grid">
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.status') }}</span>
<span class="stat-value ok">{{ stats.status }}</span>
</div>
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.mongo') }}</span>
<span class="stat-value" :class="stats.mongo === 'connected' ? 'ok' : 'bad'">{{ stats.mongo }}</span>
</div>
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.uptime') }}</span>
<span class="stat-value">{{ formatUptime(stats.uptime) }}</span>
</div>
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.memory_rss') }}</span>
<span class="stat-value">{{ formatMB(stats.memory.rss) }}</span>
</div>
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.memory_heap') }}</span>
<span class="stat-value">{{ formatMB(stats.memory.heapUsed) }}</span>
</div>
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.total_cells') }}</span>
<span class="stat-value">{{ stats.grid.totalCells }}</span>
</div>
</div>
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.mongo') }}</span>
<span class="stat-value" :class="stats.mongo === 'connected' ? 'ok' : 'bad'">{{ stats.mongo }}</span>
</div>
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.uptime') }}</span>
<span class="stat-value">{{ formatUptime(stats.uptime) }}</span>
</div>
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.memory_rss') }}</span>
<span class="stat-value">{{ formatMB(stats.memory.rss) }}</span>
</div>
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.memory_heap') }}</span>
<span class="stat-value">{{ formatMB(stats.memory.heapUsed) }}</span>
</div>
<div class="stat-card">
<span class="stat-label">{{ $t('admin.dashboard.total_cells') }}</span>
<span class="stat-value">{{ stats.grid.totalCells }}</span>
</div>
</div>
<h2 class="dash-section">{{ $t('admin.dashboard.section_orders') }} <span class="hl">[{{ orders.length }}]</span></h2>
<p v-if="!orders.length" class="dash-loading">{{ $t('admin.dashboard.orders_empty') }}</p>
<table v-else class="orders-table">
<thead>
<tr>
<th>{{ $t('admin.dashboard.col_date') }}</th>
<th>{{ $t('admin.dashboard.col_name') }}</th>
<th>{{ $t('admin.dashboard.col_email') }}</th>
<th>{{ $t('admin.dashboard.col_message') }}</th>
<th>{{ $t('admin.dashboard.col_color') }}</th>
<th>{{ $t('admin.dashboard.col_shipping') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="order in orders" :key="order._id">
<td class="nowrap">{{ formatDate(order.createdAt) }}</td>
<td>{{ order.name }} {{ order.surname }}</td>
<td>{{ order.email }}</td>
<td class="msg-cell">{{ order.message }}</td>
<td>
<span class="color-chip">
<span class="swatch" :style="{ background: orderSwatch(order) }" aria-hidden="true"></span>
{{ $t(`order.hibolia.colors.${order.color}`) }}<template v-if="order.color === 'custom'"> {{ order.customColor }}</template>
</span>
</td>
<td class="msg-cell">{{ order.shipping }}</td>
</tr>
</tbody>
</table>
</section>
</template>
</Container>
</div>
</AdminLayout>
</template>
<style lang="scss" scoped>
.dash-screen {
position: fixed;
inset: 0;
z-index: 1000;
display: flex;
background: var(--color-background);
overflow-y: auto;
}
.dash-frame {
flex: 1;
display: flex;
flex-direction: column;
--container-margin: 0;
:deep(.tui-inner) {
flex: 1;
width: 100%;
max-width: 1400px;
margin: 0 auto;
padding-bottom: 96px;
}
}
.dash-top {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.dash-title {
font-family: 'Hurmit', monospace;
margin-bottom: 8px;
}
.logout-btn {
font-family: 'Hurmit', monospace;
font-size: 0.85rem;
color: var(--color-text);
background: transparent;
border: 1px solid var(--color-border-color);
padding: 6px 14px;
cursor: pointer;
transition: all 120ms steps(3);
&:hover {
color: var(--color-link);
border-color: var(--color-link);
}
margin: 44px 0 32px;
}
.dash-welcome {
@@ -259,7 +154,7 @@ const onLogout = () => redirectToLogin();
font-family: 'Hurmit', monospace;
font-size: 1rem;
color: var(--color-link);
margin: 28px 0 12px;
margin: 64px 0 18px;
display: flex;
align-items: baseline;
gap: 16px;
@@ -270,53 +165,6 @@ const onLogout = () => redirectToLogin();
}
}
.orders-table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
th,
td {
border: 1px solid var(--color-border-color);
padding: 6px 10px;
text-align: left;
vertical-align: top;
}
th {
font-family: 'Hurmit', monospace;
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--color-link);
background: var(--color-background-line);
}
}
.nowrap {
white-space: nowrap;
}
.msg-cell {
white-space: pre-wrap;
word-break: break-word;
min-width: 200px;
}
.color-chip {
display: inline-flex;
align-items: center;
gap: 6px;
white-space: nowrap;
}
.swatch {
width: 12px;
height: 12px;
border: 1px solid var(--color-border-color);
flex-shrink: 0;
}
.stat-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));

View File

@@ -0,0 +1,204 @@
<script setup lang="ts">
import AdminLayout from '~/components/layouts/AdminLayout.vue';
definePageMeta({ middleware: 'admin-auth' });
useHead({
title: 'Hibolia Orders — Admin',
meta: [{ name: 'robots', content: 'noindex, nofollow', tagPriority: 'high' }]
});
const { getAuth } = useApi();
const auth = useAuth();
const orders = ref<any[]>([]);
const loading = ref(true);
const orderCount = useState<number | null>('admin-order-count', () => null);
watch(orders, (value) => {
orderCount.value = value.length;
});
const COLOR_HEX: Record<string, string> = {
red: '#d64545',
gold: '#d4af37',
silver: '#c0c0c0',
orange: '#e0823c',
yellow: '#e2cf3c',
green: '#5fae4e',
blue: '#4c8be0',
purple: '#9b59d0',
black: '#1a1a1a',
white: '#f2f2f2',
pink: '#e88fb3',
turquoise: '#40c4b8',
teal: '#17857c',
navy: '#34549c',
lavender: '#b98fe0',
magenta: '#cf479f',
lime: '#a8d14e',
coral: '#ef8368'
};
const orderSwatch = (order: any) =>
order.color === 'custom' ? order.customColor : COLOR_HEX[order.color] || 'transparent';
const redirectToLogin = () => {
auth.logout();
navigateTo('/admin/login');
};
const loadOrders = async () => {
try {
orders.value = await getAuth('/hibolia/orders');
} catch (e: any) {
if (e?.status === 401) {
redirectToLogin();
}
} finally {
loading.value = false;
}
};
const formatDate = (value: string) => new Date(value).toLocaleString();
onMounted(async () => {
const me = await auth.fetchMe();
if (!me) {
redirectToLogin();
return;
}
await loadOrders();
intervalId = setInterval(() => {
loadOrders();
}, 30000);
});
let intervalId: ReturnType<typeof setInterval> | null = null;
onBeforeUnmount(() => {
if (intervalId) clearInterval(intervalId);
});
</script>
<template>
<AdminLayout>
<Container class="dash-frame">
<h1 class="dash-title">{{ $t('admin.dashboard.section_orders') }} <span class="hl">[{{ orders.length }}]</span></h1>
<p v-if="loading" class="dash-loading blink">{{ $t('admin.dashboard.loading') }}</p>
<p v-if="!loading && !orders.length" class="dash-loading">{{ $t('admin.dashboard.orders_empty') }}</p>
<table v-else-if="!loading" class="orders-table">
<thead>
<tr>
<th>{{ $t('admin.dashboard.col_date') }}</th>
<th>{{ $t('admin.dashboard.col_name') }}</th>
<th>{{ $t('admin.dashboard.col_email') }}</th>
<th>{{ $t('admin.dashboard.col_message') }}</th>
<th>{{ $t('admin.dashboard.col_color') }}</th>
<th>{{ $t('admin.dashboard.col_shipping') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="order in orders" :key="order._id">
<td class="nowrap">{{ formatDate(order.createdAt) }}</td>
<td>{{ order.name }} {{ order.surname }}</td>
<td>{{ order.email }}</td>
<td class="msg-cell">{{ order.message }}</td>
<td>
<span class="color-chip">
<span class="swatch" :style="{ background: orderSwatch(order) }" aria-hidden="true"></span>
{{ $t(`order.hibolia.colors.${order.color}`) }}<template v-if="order.color === 'custom'"> {{ order.customColor }}</template>
</span>
</td>
<td class="msg-cell">{{ order.shipping }}</td>
</tr>
</tbody>
</table>
</Container>
</AdminLayout>
</template>
<style lang="scss" scoped>
.dash-frame {
--container-margin: 0;
:deep(.tui-inner) {
max-width: 1400px;
margin: 0 auto;
padding-bottom: 96px;
}
}
.dash-title {
font-family: 'Hurmit', monospace;
margin: 44px 0 32px;
.hl {
color: var(--color-text);
opacity: 0.6;
}
}
.dash-loading {
font-family: 'Hurmit', monospace;
color: var(--color-link);
margin-top: 16px;
}
.orders-table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
th,
td {
border: 1px solid var(--color-border-color);
padding: 6px 10px;
text-align: left;
vertical-align: top;
}
th {
font-family: 'Hurmit', monospace;
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--color-link);
background: var(--color-background-line);
}
}
.nowrap {
white-space: nowrap;
}
.msg-cell {
white-space: pre-wrap;
word-break: break-word;
min-width: 200px;
}
.color-chip {
display: inline-flex;
align-items: center;
gap: 6px;
white-space: nowrap;
}
.swatch {
width: 12px;
height: 12px;
border: 1px solid var(--color-border-color);
flex-shrink: 0;
}
.blink {
animation: blink 1s step-end infinite;
}
@keyframes blink {
0%, 50%, 100% { opacity: 1; }
25%, 75% { opacity: 0; }
}
</style>

View File

@@ -146,20 +146,26 @@
"error_invalid": "Accés denegat: credencials no vàlides.",
"error_generic": "L'autenticació ha fallat. Torna-ho a provar més tard."
},
"sidebar": {
"title": "ADMIN",
"nav_dashboard": "panell",
"nav_orders": "comandes",
"back_site": "veure el lloc"
},
"dashboard": {
"title": "TAULER D'ADMINISTRACIÓ",
"title": "Tauler d'administració",
"welcome": "sessió activa com a",
"logout": "tancar sessió",
"loading": "carregant dades del sistema...",
"load_error": "No s'han pogut carregar les dades del tauler.",
"section_status": "estat del sistema",
"section_status": "Estat del sistema",
"status": "estat",
"mongo": "base de dades",
"uptime": "temps actiu",
"memory_rss": "memòria (rss)",
"memory_heap": "heap usat",
"total_cells": "cel·les pintades",
"section_orders": "comandes hibolia",
"section_orders": "Comandes hibolia",
"orders_empty": "encara no hi ha comandes.",
"col_date": "data",
"col_name": "nom",

View File

@@ -146,20 +146,26 @@
"error_invalid": "Access denied: invalid credentials.",
"error_generic": "Authentication failed. Try again later."
},
"sidebar": {
"title": "ADMIN",
"nav_dashboard": "dashboard",
"nav_orders": "orders",
"back_site": "view site"
},
"dashboard": {
"title": "ADMIN DASHBOARD",
"title": "Admin dashboard",
"welcome": "session active as",
"logout": "logout",
"loading": "loading system data...",
"load_error": "Could not load dashboard data.",
"section_status": "system status",
"section_status": "System status",
"status": "status",
"mongo": "database",
"uptime": "uptime",
"memory_rss": "memory (rss)",
"memory_heap": "heap used",
"total_cells": "cells painted",
"section_orders": "hibolia orders",
"section_orders": "Hibolia orders",
"orders_empty": "no orders yet.",
"col_date": "date",
"col_name": "name",

View File

@@ -146,20 +146,26 @@
"error_invalid": "Acceso denegado: credenciales no válidas.",
"error_generic": "La autenticación ha fallado. Inténtalo más tarde."
},
"sidebar": {
"title": "ADMIN",
"nav_dashboard": "panel",
"nav_orders": "pedidos",
"back_site": "ver el sitio"
},
"dashboard": {
"title": "PANEL DE ADMINISTRACIÓN",
"title": "Panel de administración",
"welcome": "sesión activa como",
"logout": "cerrar sesión",
"loading": "cargando datos del sistema...",
"load_error": "No se pudieron cargar los datos del panel.",
"section_status": "estado del sistema",
"section_status": "Estado del sistema",
"status": "estado",
"mongo": "base de datos",
"uptime": "tiempo activo",
"memory_rss": "memoria (rss)",
"memory_heap": "heap usado",
"total_cells": "células pintadas",
"section_orders": "pedidos hibolia",
"section_orders": "Pedidos hibolia",
"orders_empty": "aún no hay pedidos.",
"col_date": "fecha",
"col_name": "nombre",

View File

@@ -146,6 +146,12 @@
"error_invalid": "访问被拒绝:凭据无效。",
"error_generic": "验证失败,请稍后再试。"
},
"sidebar": {
"title": "管理",
"nav_dashboard": "面板",
"nav_orders": "订单",
"back_site": "访问网站"
},
"dashboard": {
"title": "管理面板",
"welcome": "当前会话用户",
@@ -159,7 +165,7 @@
"memory_rss": "内存 (rss)",
"memory_heap": "已用堆内存",
"total_cells": "已绘制像素",
"section_orders": "hibolia 订单",
"section_orders": "Hibolia 订单",
"orders_empty": "暂无订单。",
"col_date": "日期",
"col_name": "姓名",

View File

@@ -44,5 +44,5 @@ export default defineNuxtConfig({
}
},
modules: ['@nuxtjs/i18n', '@nuxt/content', '@nuxt/image']
modules: ['@nuxtjs/i18n', '@nuxt/content', '@nuxt/image', '@nuxtjs/turnstile']
})

View File

@@ -9,7 +9,9 @@
"dependencies": {
"@nuxt/content": "^3.12.0",
"@nuxt/image": "^2.0.0",
"@nuxt/scripts": "^1.3.9",
"@nuxtjs/i18n": "10.2.3",
"@nuxtjs/turnstile": "^1.1.3",
"better-sqlite3": "^12.10.0",
"nuxt": "^4.3.1",
"sass": "^1.98.0",
@@ -704,28 +706,31 @@
"integrity": "sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ=="
},
"node_modules/@emnapi/core": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz",
"integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==",
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz",
"integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==",
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.2.0",
"@emnapi/wasi-threads": "1.2.2",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz",
"integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==",
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz",
"integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==",
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/wasi-threads": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz",
"integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==",
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
"integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
@@ -2153,9 +2158,10 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz",
"integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==",
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.31",
@@ -2218,18 +2224,24 @@
}
},
"node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz",
"integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.4.tgz",
"integrity": "sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==",
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.7.1",
"@emnapi/runtime": "^1.7.1",
"@tybys/wasm-util": "^0.10.1"
"@tybys/wasm-util": "^0.10.3"
},
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=23.5.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
},
"peerDependencies": {
"@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4",
"@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4"
}
},
"node_modules/@nodelib/fs.scandir": {
@@ -2597,6 +2609,568 @@
"node": "^14.18.0 || >=16.10.0"
}
},
"node_modules/@nuxt/scripts": {
"version": "1.3.9",
"resolved": "https://registry.npmjs.org/@nuxt/scripts/-/scripts-1.3.9.tgz",
"integrity": "sha512-6OIvXXZ736YHtF7qLueO0foxQvhLhhjJ4zifBEhxAV7ouxI/NStmLIz70pQiPdhr26/1JZqHgGVfC91vJZPZIg==",
"license": "MIT",
"dependencies": {
"@nuxt/devtools-kit": "^3.2.4",
"@vueuse/core": "^14.3.0",
"@vueuse/shared": "^14.3.0",
"consola": "^3.4.2",
"defu": "^6.1.7",
"h3": "^1.15.11",
"magic-string": "^1.0.0",
"ofetch": "^1.5.1",
"ohash": "^2.0.11",
"oxc-parser": "^0.140.0",
"oxc-walker": "^1.0.0",
"pathe": "^2.0.3",
"pkg-types": "^2.3.1",
"sirv": "^3.0.2",
"std-env": "^4.2.0",
"ufo": "^1.6.4",
"ultrahtml": "^1.7.0",
"undici": "^6.27.0",
"unplugin": "^3.3.0",
"unstorage": "^1.17.5",
"valibot": "^1.4.2"
},
"bin": {
"nuxt-scripts": "bin/cli.mjs"
},
"peerDependencies": {
"@googlemaps/markerclusterer": "^2.6.2",
"@paypal/paypal-js": "^8.1.2 || ^9.0.0",
"@speedcurve/lux": "^4.4.3",
"@stripe/stripe-js": "^7.0.0 || ^8.0.0 || ^9.0.0",
"@types/google.maps": "^3.58.1",
"@types/vimeo__player": "^2.18.3",
"@types/youtube": "^0.1.0",
"@unhead/vue": "^2.0.3 || ^3.0.0",
"posthog-js": "^1.0.0"
},
"peerDependenciesMeta": {
"@googlemaps/markerclusterer": {
"optional": true
},
"@paypal/paypal-js": {
"optional": true
},
"@speedcurve/lux": {
"optional": true
},
"@stripe/stripe-js": {
"optional": true
},
"@types/google.maps": {
"optional": true
},
"@types/vimeo__player": {
"optional": true
},
"@types/youtube": {
"optional": true
},
"@unhead/vue": {
"optional": true
},
"posthog-js": {
"optional": true
}
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-android-arm-eabi": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.140.0.tgz",
"integrity": "sha512-ZfjDZ422mo7eo3b3VltqNsV9kmv1qt/sPEAMSl64iOSwhVfd0eIZ9LB79Mbs1xYXJnk7WSROwzBCKDIiVxPTvQ==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-android-arm64": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.140.0.tgz",
"integrity": "sha512-Ia8jSvikUX6Sf+Ht+KOCUF/k1HpR0VlmqIYymubmWDebOEGtsyliHDR6JxsZ4IX3/c/GbrB1uh09aVGQv/LQmQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-darwin-arm64": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.140.0.tgz",
"integrity": "sha512-G6VK0nK61pH0d0mBjUqSZbVxGqqO5uzeginLDQj+gOO6ObfJjXRwgkD/ol0w1INcnFeAb6YGGO7qc3ueGHaycQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-darwin-x64": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.140.0.tgz",
"integrity": "sha512-HazBOuZzd2pO1C2uMmp8Gv7mhzMHqKSKDS1OZfcLEvpIcgA+48J92HEtNanVHDIzRD9PRPCV6aS6fkZIWOVl8Q==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-freebsd-x64": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.140.0.tgz",
"integrity": "sha512-9hSUU+HmTUyOe4JzMHxNGgLWNY7rrO+6ShicZwImNJacEAACDMIkuEQQkvXSL+WJN50jaNtLYJv8s4OcBdpyUQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-linux-arm-gnueabihf": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.140.0.tgz",
"integrity": "sha512-RAEuQsYtS0KcDFqN0ABTjyyNlokS91JeuDuoW9tEbG0JTbRNXnpQUdbYc/16JoA6Z/2ALbNrE3KmxtqDiuIjCQ==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-linux-arm-musleabihf": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.140.0.tgz",
"integrity": "sha512-c4CkHvPvqfojouredJ0w3e6+jiBq0SbFyhH61kr/zPb/7XsaYTNKQ54vmlSsopfdQbNDX40ZeK9Abs2Qet6wcw==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-linux-arm64-gnu": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.140.0.tgz",
"integrity": "sha512-yrjmLj8ixPB25yqvPGr28meGjb+keed7m1GqqY/0uqkhZIoT4t9zmfwUgFEtC33C7dtE+UQ7TU0IaVxf97SWJg==",
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-linux-arm64-musl": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.140.0.tgz",
"integrity": "sha512-ggGMQTN8Agwxp2WiLMpdY671dt0qTDJWiWlJeig3HnUwTnerRl0J2JdGVghWBeDcss2D9S2V2Js6dZHEiVabVA==",
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-linux-ppc64-gnu": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.140.0.tgz",
"integrity": "sha512-IgTs8xYAFgAUGNmR65tIqjlJ8vKgrfXzC515e9goSdfMyKQV4aJpd2pUUudU4u51G64H0/DSEJEXKOraxm9ZCA==",
"cpu": [
"ppc64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-linux-riscv64-gnu": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.140.0.tgz",
"integrity": "sha512-A1x+PMWZmSGaFVOx2YeNTFau8uD+QO14/vLP4GrcuvUPs3+nBkUOjy9Lus86ftHsDojjYMbvBelmKc3F7Rv08g==",
"cpu": [
"riscv64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-linux-riscv64-musl": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.140.0.tgz",
"integrity": "sha512-zBqpfRo2myWPrPo5xUjeZqlnPXPXsX8BcWtWff66/eGRQdbPjhzPgXa/F+AtxT2afUViPxbuDlwscMKzQ5tg+g==",
"cpu": [
"riscv64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-linux-s390x-gnu": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.140.0.tgz",
"integrity": "sha512-2M1DPm/8w9I//YzFlFC9qXw+r2tJFh5CYwRlYTq2vUJQS7qoQftEDeCZ8EnN7KHtvSiXvYj8mZI5pR7DpXmcEw==",
"cpu": [
"s390x"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-linux-x64-gnu": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.140.0.tgz",
"integrity": "sha512-8aRDbZ/U/jO8N7go1MO72jtbpb4uswV8d7vOkMvt/BPgZiyEYvl1VIWK4ESxZZhnJ4tqwVldgX7dNiP/eB1Jdg==",
"cpu": [
"x64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-linux-x64-musl": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.140.0.tgz",
"integrity": "sha512-xRqpeI8U2sQQS1W5BMWRyMTxtagkuLG2dEWruet5lFsWHTvBth11/TpSaJatHdqVVwHN0q3uuoS9zRsGinq8hg==",
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-openharmony-arm64": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.140.0.tgz",
"integrity": "sha512-GbGRe26MqAKciFRvXeHNQJ6VAHYs9R4miP89sEAncysM3n+f4lnyLWgsa9kklJNpfnxdq2yRoNYHFqwBckVimw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-wasm32-wasi": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.140.0.tgz",
"integrity": "sha512-vFiC1hqys+hkX1GnQkIoiTQJNiUm43Z0lO35ETKXTw0YtpW7+cN58YRRXFAQQ+TgpkIi3lrhcxdlnqz+Oi3ptQ==",
"cpu": [
"wasm32"
],
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "1.11.2",
"@emnapi/runtime": "1.11.2",
"@napi-rs/wasm-runtime": "^1.1.6"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-win32-arm64-msvc": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.140.0.tgz",
"integrity": "sha512-fGSQldwEYKhM+H8uLt76Op8hh5+FYaR6lvvQ1Txw3Mhn86DyQXLcI0fi1EkFlTK7F+46OCk/j0AJMzZQm6g5Xg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-win32-ia32-msvc": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.140.0.tgz",
"integrity": "sha512-sDS2Bai+g3ZWYwfZqmosiSuFDBcVnZ3Ta6pszzsiJoLMqsJEWKcxXXbGa7b7yXr++W2lQNPb3ZRJ8czseqL7RA==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-parser/binding-win32-x64-msvc": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.140.0.tgz",
"integrity": "sha512-kHbE1zWyb5OQgJA6/5P4WjiuB01sYdQwtZnSSyE58FQEXDAMnyeeq4vj7KgN75i5SlBzOs8A5MrtlD3gOlDKqQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@nuxt/scripts/node_modules/@oxc-project/types": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.140.0.tgz",
"integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/Boshen"
}
},
"node_modules/@nuxt/scripts/node_modules/magic-string": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.1.tgz",
"integrity": "sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==",
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.6.0"
}
},
"node_modules/@nuxt/scripts/node_modules/oxc-parser": {
"version": "0.140.0",
"resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.140.0.tgz",
"integrity": "sha512-h6QFWd6lBMfjESqgQ27GjzrSDb0qbznp7VDQqp2zvgsrWut4vcchyMIzOVXvGQ2GMZgKw9RWrFNWv9WqGL0p7Q==",
"license": "MIT",
"dependencies": {
"@oxc-project/types": "^0.140.0"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"funding": {
"url": "https://github.com/sponsors/Boshen"
},
"optionalDependencies": {
"@oxc-parser/binding-android-arm-eabi": "0.140.0",
"@oxc-parser/binding-android-arm64": "0.140.0",
"@oxc-parser/binding-darwin-arm64": "0.140.0",
"@oxc-parser/binding-darwin-x64": "0.140.0",
"@oxc-parser/binding-freebsd-x64": "0.140.0",
"@oxc-parser/binding-linux-arm-gnueabihf": "0.140.0",
"@oxc-parser/binding-linux-arm-musleabihf": "0.140.0",
"@oxc-parser/binding-linux-arm64-gnu": "0.140.0",
"@oxc-parser/binding-linux-arm64-musl": "0.140.0",
"@oxc-parser/binding-linux-ppc64-gnu": "0.140.0",
"@oxc-parser/binding-linux-riscv64-gnu": "0.140.0",
"@oxc-parser/binding-linux-riscv64-musl": "0.140.0",
"@oxc-parser/binding-linux-s390x-gnu": "0.140.0",
"@oxc-parser/binding-linux-x64-gnu": "0.140.0",
"@oxc-parser/binding-linux-x64-musl": "0.140.0",
"@oxc-parser/binding-openharmony-arm64": "0.140.0",
"@oxc-parser/binding-wasm32-wasi": "0.140.0",
"@oxc-parser/binding-win32-arm64-msvc": "0.140.0",
"@oxc-parser/binding-win32-ia32-msvc": "0.140.0",
"@oxc-parser/binding-win32-x64-msvc": "0.140.0"
}
},
"node_modules/@nuxt/scripts/node_modules/oxc-walker": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/oxc-walker/-/oxc-walker-1.1.1.tgz",
"integrity": "sha512-Hwd7dq28zu/Er99+bpWp16CGwFrhyalJh0W3JOB7XpPvgWo3MqMi2ksWGKuzzA9zt50mJ2pIUwR5lpAdZ9ACNQ==",
"license": "MIT",
"peerDependencies": {
"@oxc-project/types": ">=0.98.0",
"oxc-parser": ">=0.98.0",
"rolldown": ">=1.0.0"
},
"peerDependenciesMeta": {
"@oxc-project/types": {
"optional": true
},
"oxc-parser": {
"optional": true
},
"rolldown": {
"optional": true
}
}
},
"node_modules/@nuxt/scripts/node_modules/undici": {
"version": "6.28.1",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.28.1.tgz",
"integrity": "sha512-zWpdTVD54H48CIybL0rWQ3ukpb9d23wM7eH5RtfdmeP70cWHNjtfo7P4vZX+5CoDcO53J4Pu5uXp7lNfjc6DRA==",
"license": "MIT",
"engines": {
"node": ">=18.17"
}
},
"node_modules/@nuxt/scripts/node_modules/unplugin": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.4.0.tgz",
"integrity": "sha512-9skdIFlCsPdFV7wUfZxNsFInlW+7nJmGu2gkTu0OUhF56aXGsHab9x52/QhdJ4lC7ZDPWTxbiC4ANqVlsuaW3w==",
"license": "MIT",
"dependencies": {
"@jridgewell/remapping": "^2.3.5",
"picomatch": "^4.0.7",
"webpack-virtual-modules": "^0.6.2"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"peerDependencies": {
"@farmfe/core": "*",
"@rsbuild/core": "*",
"@rspack/core": "*",
"bun-types-no-globals": "*",
"esbuild": "*",
"rolldown": "*",
"rollup": "*",
"unloader": "*",
"vite": "*",
"webpack": "*"
},
"peerDependenciesMeta": {
"@farmfe/core": {
"optional": true
},
"@rsbuild/core": {
"optional": true
},
"@rspack/core": {
"optional": true
},
"bun-types-no-globals": {
"optional": true
},
"esbuild": {
"optional": true
},
"rolldown": {
"optional": true
},
"rollup": {
"optional": true
},
"unloader": {
"optional": true
},
"vite": {
"optional": true
},
"webpack": {
"optional": true
}
}
},
"node_modules/@nuxt/telemetry": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/@nuxt/telemetry/-/telemetry-2.7.0.tgz",
@@ -3015,6 +3589,53 @@
"@types/hast": "^3.0.4"
}
},
"node_modules/@nuxtjs/turnstile": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@nuxtjs/turnstile/-/turnstile-1.1.3.tgz",
"integrity": "sha512-NKiRHvdCuuWz85VHWzhofPXxHFq6y2eOHXQPsrRJhLnEZ/YBvGt6beOxI0M50rHKMEmdYjM/30QomyzNLIBz4w==",
"license": "MIT",
"dependencies": {
"@nuxt/kit": "^3.16.0",
"@types/cloudflare-turnstile": "0.2.2",
"defu": "^6.1.4",
"pathe": "^2.0.3"
},
"peerDependencies": {
"@nuxt/scripts": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^1.0.0"
}
},
"node_modules/@nuxtjs/turnstile/node_modules/@nuxt/kit": {
"version": "3.21.11",
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.21.11.tgz",
"integrity": "sha512-0Xi3tgwN77w43Q8GCPIrvWmF1J7Peehkts44E0uKNIml9lB8WoUn8YxyUjxBv47XtVR86NWoWALAT+/IEMHJEA==",
"license": "MIT",
"dependencies": {
"c12": "^3.3.4",
"consola": "^3.4.2",
"defu": "^6.1.7",
"destr": "^2.0.5",
"errx": "^0.1.2",
"exsolve": "^1.1.1",
"ignore": "^7.0.6",
"jiti": "^2.7.0",
"klona": "^2.0.6",
"knitwork": "^1.3.0",
"mlly": "^1.8.2",
"ohash": "^2.0.11",
"pathe": "^2.0.3",
"pkg-types": "^2.3.1",
"rc9": "^3.0.1",
"scule": "^1.3.0",
"semver": "^7.8.5",
"tinyglobby": "^0.2.17",
"ufo": "^1.6.4",
"unctx": "^2.5.0",
"untyped": "^2.0.0"
},
"engines": {
"node": ">=18.12.0"
}
},
"node_modules/@one-ini/wasm": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz",
@@ -5250,9 +5871,10 @@
"license": "MIT"
},
"node_modules/@tybys/wasm-util": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
"version": "0.10.4",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz",
"integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==",
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
@@ -5276,6 +5898,12 @@
"assertion-error": "^2.0.1"
}
},
"node_modules/@types/cloudflare-turnstile": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@types/cloudflare-turnstile/-/cloudflare-turnstile-0.2.2.tgz",
"integrity": "sha512-3Yf7b1Glci+V2bFWwWBbZkRgTuegp7RDgNTOG4U0UNPB9RV4AWvwqg2/qqLff8G+SwKFNXoXvTkqaRBZrAFdKA==",
"license": "MIT"
},
"node_modules/@types/debug": {
"version": "4.1.12",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
@@ -5387,6 +6015,12 @@
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
"license": "MIT"
},
"node_modules/@types/web-bluetooth": {
"version": "0.0.21",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
"integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
"license": "MIT"
},
"node_modules/@types/webxr": {
"version": "0.5.24",
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz",
@@ -6001,6 +6635,44 @@
}
}
},
"node_modules/@vueuse/core": {
"version": "14.4.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.4.0.tgz",
"integrity": "sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ==",
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.21",
"@vueuse/metadata": "14.4.0",
"@vueuse/shared": "14.4.0"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"vue": "^3.5.0"
}
},
"node_modules/@vueuse/metadata": {
"version": "14.4.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.4.0.tgz",
"integrity": "sha512-swx/255R6JyHZFJhx845iz5CRWDZdCfvkZOpACWc5+c5WHcG24mv8gUT1WIdFQaHt6dq79rvILd9QnCWiyVm9g==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared": {
"version": "14.4.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.4.0.tgz",
"integrity": "sha512-JRgY90Sz8DDtPMsaDflvPMp9xYk69JZAmbuDvAquUVXKr2gEjqtzGNTTthLfckH0BzBqvnu31gb4a8TGLRe79g==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"vue": "^3.5.0"
}
},
"node_modules/@webcontainer/env": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@webcontainer/env/-/env-1.1.1.tgz",
@@ -7144,9 +7816,10 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
},
"node_modules/cookie-es": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz",
"integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz",
"integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==",
"license": "MIT"
},
"node_modules/core-util-is": {
"version": "1.0.3",
@@ -8045,9 +8718,10 @@
}
},
"node_modules/errx": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/errx/-/errx-0.1.0.tgz",
"integrity": "sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q=="
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/errx/-/errx-0.1.2.tgz",
"integrity": "sha512-chfpPHmCerdo/rXr/nNvPZRkV4WwDRwzwnsJ0Uzz3tVi8Z41tDctRjduYy1138ii77AFlts1qvWtX3g/Acg91Q==",
"license": "MIT"
},
"node_modules/es-define-property": {
"version": "1.0.1",
@@ -8462,9 +9136,10 @@
}
},
"node_modules/exsolve": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz",
"integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.1.tgz",
"integrity": "sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==",
"license": "MIT"
},
"node_modules/extend": {
"version": "3.0.2",
@@ -8950,13 +9625,14 @@
}
},
"node_modules/h3": {
"version": "1.15.8",
"resolved": "https://registry.npmjs.org/h3/-/h3-1.15.8.tgz",
"integrity": "sha512-iOH6Vl8mGd9nNfu9C0IZ+GuOAfJHcyf3VriQxWaSWIB76Fg4BnFuk4cxBxjmQSSxJS664+pgjP6e7VBnUzFfcg==",
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz",
"integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==",
"license": "MIT",
"dependencies": {
"cookie-es": "^1.2.2",
"cookie-es": "^1.2.3",
"crossws": "^0.3.5",
"defu": "^6.1.4",
"defu": "^6.1.6",
"destr": "^2.0.5",
"iron-webcrypto": "^1.2.1",
"node-mock-http": "^1.0.4",
@@ -9496,9 +10172,10 @@
]
},
"node_modules/ignore": {
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
"version": "7.0.9",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.9.tgz",
"integrity": "sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw==",
"license": "MIT",
"engines": {
"node": ">= 4"
}
@@ -14282,9 +14959,9 @@
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"node_modules/picomatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz",
"integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
"license": "MIT",
"engines": {
"node": ">=12"
@@ -15665,9 +16342,9 @@
"integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g=="
},
"node_modules/semver": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.3.tgz",
"integrity": "sha512-wnilbGyMxzbY7dNOl7jpKbLSjcfeweJWU5j4+u5qW+6/wuGD9KzIGOyZnQVSBM9E7DtWaaH3CyHkppYrKYoxwg==",
"version": "7.8.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -16255,9 +16932,10 @@
}
},
"node_modules/std-env": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz",
"integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ=="
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz",
"integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==",
"license": "MIT"
},
"node_modules/stop-iteration-iterator": {
"version": "1.1.0",
@@ -16911,9 +17589,10 @@
"license": "MIT"
},
"node_modules/ultrahtml": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz",
"integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw=="
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.7.0.tgz",
"integrity": "sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g==",
"license": "MIT"
},
"node_modules/uncrypto": {
"version": "0.1.3",
@@ -17275,15 +17954,16 @@
}
},
"node_modules/unstorage": {
"version": "1.17.4",
"resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.4.tgz",
"integrity": "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==",
"version": "1.17.5",
"resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz",
"integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==",
"license": "MIT",
"dependencies": {
"anymatch": "^3.1.3",
"chokidar": "^5.0.0",
"destr": "^2.0.5",
"h3": "^1.15.5",
"lru-cache": "^11.2.0",
"h3": "^1.15.10",
"lru-cache": "^11.2.7",
"node-fetch-native": "^1.6.7",
"ofetch": "^1.5.1",
"ufo": "^1.6.3"
@@ -17471,6 +18151,20 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/valibot": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/valibot/-/valibot-1.5.0.tgz",
"integrity": "sha512-nil6AkP2TChWL43Z5uJ6GTxX01CUA+g8LWUM+N/rB9NBbkUMaUsi9PUNzlUPgoKASgmx9f7eGOYpJ04/fSa6FQ==",
"license": "MIT",
"peerDependencies": {
"typescript": ">=5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/vfile": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",

View File

@@ -14,7 +14,9 @@
"dependencies": {
"@nuxt/content": "^3.12.0",
"@nuxt/image": "^2.0.0",
"@nuxt/scripts": "^1.3.9",
"@nuxtjs/i18n": "10.2.3",
"@nuxtjs/turnstile": "^1.1.3",
"better-sqlite3": "^12.10.0",
"nuxt": "^4.3.1",
"sass": "^1.98.0",