feat(frontend): Vue 3 workspace UI with light/dark mode
- Vue 3 + Vite + Pinia + Vue Router, Axios client with JWT interceptor - Auth views (login/register), dashboard with workspace switcher and search - Nested PageTree sidebar, TipTap rich-text editor with debounced save - Live collaboration via Socket.IO (remote updates, presence avatars, typing) - Comments thread per page, invite-members card, member list - Theme store (light/dark/system) persisted, CSS variables, ThemeToggle - Multi-stage Dockerfile (build + nginx) for hosting
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useAuthStore } from '../stores/auth';
|
||||
|
||||
const email = ref('');
|
||||
const name = ref('');
|
||||
const password = ref('');
|
||||
const err = ref('');
|
||||
const router = useRouter();
|
||||
const auth = useAuthStore();
|
||||
|
||||
async function submit() {
|
||||
err.value = '';
|
||||
try {
|
||||
await auth.register(email.value, name.value, password.value);
|
||||
router.push('/');
|
||||
} catch (e) {
|
||||
err.value = e.response?.data?.error || 'Registration failed';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="auth-wrap card">
|
||||
<h1>Create account</h1>
|
||||
<p class="muted">Start your collaborative workspace.</p>
|
||||
<form @submit.prevent="submit" style="display: grid; gap: 10px">
|
||||
<input v-model="name" placeholder="Display name" required />
|
||||
<input v-model="email" type="email" placeholder="Email" required />
|
||||
<input v-model="password" type="password" placeholder="Password (min 8 chars)" required minlength="8" />
|
||||
<button type="submit">Register</button>
|
||||
</form>
|
||||
<p v-if="err" style="color: red">{{ err }}</p>
|
||||
<p class="muted">Have an account? <router-link to="/login">Log in</router-link></p>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user