Enhance frontend UI and functionality
- Added page transition effects in app.vue for smoother navigation. - Updated nuxt.config.ts to include custom font styles and page transitions. - Improved loading indicators in MapPageWrapper.vue and login.vue for better user experience. - Enhanced MapView.vue with a collapsible control panel and improved styling. - Introduced new icons for various components to enhance visual consistency. - Updated Tailwind CSS configuration to extend font families and improve theme management. - Refined layout styles in default.vue and admin pages for better responsiveness and aesthetics. - Implemented error handling and loading states across various forms for improved user feedback.
This commit is contained in:
@@ -4,49 +4,68 @@
|
||||
|
||||
<div
|
||||
v-if="message.text"
|
||||
class="mb-4 rounded-lg px-4 py-2"
|
||||
class="mb-4 rounded-lg px-4 py-2 transition-all duration-300"
|
||||
:class="message.type === 'error' ? 'bg-error/20 text-error' : 'bg-success/20 text-success'"
|
||||
role="alert"
|
||||
>
|
||||
{{ message.text }}
|
||||
</div>
|
||||
|
||||
<div class="card bg-base-200 shadow-xl mb-6">
|
||||
<div class="card bg-base-200 shadow-xl mb-6 transition-all duration-200">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Users</h2>
|
||||
<ul class="space-y-2">
|
||||
<li
|
||||
<h2 class="card-title gap-2">
|
||||
<icons-icon-users />
|
||||
Users
|
||||
</h2>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div
|
||||
v-for="u in users"
|
||||
:key="u"
|
||||
class="flex justify-between items-center gap-3 py-1 border-b border-base-300 last:border-0"
|
||||
class="flex items-center justify-between gap-3 w-full p-3 rounded-lg bg-base-300/50 hover:bg-base-300/70 transition-colors"
|
||||
>
|
||||
<span>{{ u }}</span>
|
||||
<NuxtLink :to="`/admin/users/${u}`" class="btn btn-ghost btn-xs">Edit</NuxtLink>
|
||||
</li>
|
||||
<li v-if="!users.length" class="py-1 text-base-content/60">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<div class="avatar placeholder">
|
||||
<div class="bg-neutral text-neutral-content rounded-full w-8">
|
||||
<span class="text-xs">{{ u[0]?.toUpperCase() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="font-medium">{{ u }}</span>
|
||||
</div>
|
||||
<NuxtLink :to="`/admin/users/${u}`" class="btn btn-outline btn-sm gap-1 shrink-0">
|
||||
<icons-icon-pencil /> Edit
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div v-if="!users.length" class="py-6 text-center text-base-content/60 rounded-lg bg-base-300/30">
|
||||
No users yet.
|
||||
</li>
|
||||
</ul>
|
||||
<NuxtLink to="/admin/users/new" class="btn btn-primary btn-sm mt-2">Add user</NuxtLink>
|
||||
</div>
|
||||
<NuxtLink to="/admin/users/new" class="btn btn-primary btn-sm mt-2 gap-1">
|
||||
<icons-icon-plus /> Add user
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-base-200 shadow-xl mb-6">
|
||||
<div class="card bg-base-200 shadow-xl mb-6 transition-all duration-200">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Maps</h2>
|
||||
<h2 class="card-title gap-2">
|
||||
<icons-icon-map-pin />
|
||||
Maps
|
||||
</h2>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table table-sm">
|
||||
<table class="table table-sm table-zebra">
|
||||
<thead>
|
||||
<tr><th>ID</th><th>Name</th><th>Hidden</th><th>Priority</th><th></th></tr>
|
||||
<tr><th>ID</th><th>Name</th><th>Hidden</th><th>Priority</th><th class="text-right"></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="map in maps" :key="map.ID">
|
||||
<tr v-for="map in maps" :key="map.ID" class="hover">
|
||||
<td>{{ map.ID }}</td>
|
||||
<td>{{ map.Name }}</td>
|
||||
<td>{{ map.Hidden ? 'Yes' : 'No' }}</td>
|
||||
<td>{{ map.Priority ? 'Yes' : 'No' }}</td>
|
||||
<td>
|
||||
<NuxtLink :to="`/admin/maps/${map.ID}`" class="btn btn-ghost btn-xs">Edit</NuxtLink>
|
||||
<td class="text-right">
|
||||
<NuxtLink :to="`/admin/maps/${map.ID}`" class="btn btn-outline btn-sm gap-1">
|
||||
<icons-icon-pencil /> Edit
|
||||
</NuxtLink>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="!maps.length">
|
||||
@@ -58,9 +77,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-base-200 shadow-xl mb-6">
|
||||
<div class="card bg-base-200 shadow-xl mb-6 transition-all duration-200">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Settings</h2>
|
||||
<h2 class="card-title gap-2">
|
||||
<icons-icon-settings />
|
||||
Settings
|
||||
</h2>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="form-control w-full max-w-xs">
|
||||
<label class="label" for="admin-settings-prefix">Prefix</label>
|
||||
@@ -93,16 +115,20 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end mt-2">
|
||||
<button class="btn btn-sm" :disabled="savingSettings" @click="saveSettings">
|
||||
{{ savingSettings ? '…' : 'Save settings' }}
|
||||
<button class="btn btn-primary btn-sm" :disabled="savingSettings" @click="saveSettings">
|
||||
<span v-if="savingSettings" class="loading loading-spinner loading-sm" />
|
||||
<span v-else>Save settings</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-base-200 shadow-xl mb-6">
|
||||
<div class="card bg-base-200 shadow-xl mb-6 transition-all duration-200">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Actions</h2>
|
||||
<h2 class="card-title gap-2">
|
||||
<icons-icon-alert-triangle />
|
||||
Actions
|
||||
</h2>
|
||||
<div class="flex flex-col gap-3">
|
||||
<div>
|
||||
<a :href="api.adminExportUrl()" target="_blank" rel="noopener" class="btn btn-sm">
|
||||
@@ -111,7 +137,8 @@
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn btn-sm" :disabled="rebuilding" @click="rebuildZooms">
|
||||
{{ rebuilding ? '…' : 'Rebuild zooms' }}
|
||||
<span v-if="rebuilding" class="loading loading-spinner loading-sm" />
|
||||
<span v-else>Rebuild zooms</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
@@ -126,14 +153,16 @@
|
||||
</div>
|
||||
<form @submit.prevent="doMerge">
|
||||
<button type="submit" class="btn btn-sm btn-primary" :disabled="!mergeFile || merging">
|
||||
{{ merging ? '…' : 'Merge' }}
|
||||
<span v-if="merging" class="loading loading-spinner loading-sm" />
|
||||
<span v-else>Merge</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="border-t border-base-300 pt-4 mt-1">
|
||||
<div class="border-t border-red-500/30 pt-4 mt-1 bg-error/5 rounded-lg p-3 -mx-1">
|
||||
<p class="text-sm font-medium text-error/90 mb-2">Danger zone</p>
|
||||
<button class="btn btn-sm btn-error" :disabled="wiping" @click="confirmWipe">
|
||||
{{ wiping ? '…' : 'Wipe all data' }}
|
||||
<span v-if="wiping" class="loading loading-spinner loading-sm" />
|
||||
<span v-else>Wipe all data</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,7 +21,10 @@
|
||||
</div>
|
||||
<p v-if="error" class="text-error text-sm">{{ error }}</p>
|
||||
<div class="flex gap-2">
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">{{ loading ? '…' : 'Save' }}</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
<span v-if="loading" class="loading loading-spinner loading-sm" />
|
||||
<span v-else>Save</span>
|
||||
</button>
|
||||
<NuxtLink to="/admin" class="btn btn-ghost">Back</NuxtLink>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -30,7 +30,10 @@
|
||||
</div>
|
||||
<p v-if="error" class="text-error text-sm">{{ error }}</p>
|
||||
<div class="flex gap-2">
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">{{ loading ? '…' : 'Save' }}</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
<span v-if="loading" class="loading loading-spinner loading-sm" />
|
||||
<span v-else>Save</span>
|
||||
</button>
|
||||
<NuxtLink to="/admin" class="btn btn-ghost">Back</NuxtLink>
|
||||
<button
|
||||
v-if="!isNew"
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="min-h-screen flex flex-col items-center justify-center bg-base-200 p-4 overflow-hidden">
|
||||
<div class="card w-full max-w-sm bg-base-100 shadow-xl">
|
||||
<div class="min-h-screen flex flex-col items-center justify-center bg-gradient-to-br from-base-200 via-base-300 to-primary/10 p-4 overflow-hidden">
|
||||
<div class="card w-full max-w-sm bg-base-100 shadow-2xl ring-1 ring-base-300 login-card">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title justify-center">Log in</h1>
|
||||
<h1 class="card-title justify-center text-2xl">HnH Map</h1>
|
||||
<p class="text-center text-base-content/70 text-sm">Log in to continue</p>
|
||||
<form @submit.prevent="submit" class="flex flex-col gap-4">
|
||||
<div class="form-control">
|
||||
<label class="label" for="user">User</label>
|
||||
@@ -22,8 +23,9 @@
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
<p v-if="error" class="text-error text-sm">{{ error }}</p>
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
{{ loading ? '…' : 'Log in' }}
|
||||
<button type="submit" class="btn btn-primary transition-all duration-200 hover:scale-[1.02]" :disabled="loading">
|
||||
<span v-if="loading" class="loading loading-spinner loading-sm" />
|
||||
<span v-else>Log in</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
<div class="container mx-auto p-4 max-w-2xl">
|
||||
<h1 class="text-2xl font-bold mb-6">Profile</h1>
|
||||
|
||||
<div class="card bg-base-200 shadow-xl mb-6">
|
||||
<div class="card bg-base-200 shadow-xl mb-6 transition-all duration-200">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Upload tokens</h2>
|
||||
<h2 class="card-title gap-2">
|
||||
<icons-icon-key />
|
||||
Upload tokens
|
||||
</h2>
|
||||
<p class="text-sm opacity-80">Tokens for upload API. Generate and copy as needed.</p>
|
||||
<ul v-if="tokens?.length" class="list-disc list-inside mt-2 space-y-1">
|
||||
<li v-for="t in tokens" :key="t" class="font-mono text-sm flex items-center gap-2">
|
||||
@@ -21,15 +24,18 @@
|
||||
</ul>
|
||||
<p v-else class="text-sm mt-2">No tokens yet.</p>
|
||||
<p v-if="tokenError" class="text-error text-sm mt-2">{{ tokenError }}</p>
|
||||
<button class="btn btn-primary btn-sm mt-2" :disabled="loadingTokens" @click="generateToken">
|
||||
<button class="btn btn-primary btn-sm mt-2 transition-all duration-200 hover:scale-[1.02]" :disabled="loadingTokens" @click="generateToken">
|
||||
{{ loadingTokens ? '…' : 'Generate token' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-base-200 shadow-xl mb-6">
|
||||
<div class="card bg-base-200 shadow-xl mb-6 transition-all duration-200">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">Change password</h2>
|
||||
<h2 class="card-title gap-2">
|
||||
<icons-icon-settings />
|
||||
Change password
|
||||
</h2>
|
||||
<form @submit.prevent="changePass" class="flex flex-col gap-2">
|
||||
<PasswordInput
|
||||
v-model="newPass"
|
||||
@@ -37,7 +43,7 @@
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
<p v-if="passMsg" class="text-sm" :class="passOk ? 'text-success' : 'text-error'">{{ passMsg }}</p>
|
||||
<button type="submit" class="btn btn-sm" :disabled="loadingPass">Save password</button>
|
||||
<button type="submit" class="btn btn-sm transition-all duration-200 hover:scale-[1.02]" :disabled="loadingPass">Save password</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
/>
|
||||
<p v-if="error" class="text-error text-sm">{{ error }}</p>
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
{{ loading ? '…' : 'Create and log in' }}
|
||||
<span v-if="loading" class="loading loading-spinner loading-sm" />
|
||||
<span v-else>Create and log in</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user