phase 5
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
node_modules/
|
||||
dist/
|
||||
build/
|
||||
.svelte-kit/
|
||||
coverage/
|
||||
*.min.js
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
||||
.DS_Store
|
||||
|
||||
@@ -48,4 +48,3 @@ module.exports = {
|
||||
'svelte/no-target-blank': 'error'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
63
frontend/eslint.config.js
Normal file
63
frontend/eslint.config.js
Normal file
@@ -0,0 +1,63 @@
|
||||
// ESLint v9 Flat Config
|
||||
import tseslint from 'typescript-eslint';
|
||||
import svelte from 'eslint-plugin-svelte';
|
||||
import prettier from 'eslint-config-prettier';
|
||||
import globals from 'globals';
|
||||
|
||||
export default [
|
||||
// Ignore patterns
|
||||
{
|
||||
ignores: [
|
||||
'**/node_modules/**',
|
||||
'**/dist/**',
|
||||
'**/build/**',
|
||||
'**/.svelte-kit/**',
|
||||
'**/coverage/**',
|
||||
'**/*.min.js',
|
||||
],
|
||||
},
|
||||
|
||||
// Base recommended configs
|
||||
...tseslint.configs.recommended,
|
||||
...svelte.configs['flat/recommended'],
|
||||
prettier,
|
||||
|
||||
// Configuration for all files
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'no-console': ['warn', { allow: ['warn', 'error'] }],
|
||||
'prefer-const': 'error',
|
||||
'no-var': 'error',
|
||||
},
|
||||
},
|
||||
|
||||
// Svelte-specific config
|
||||
{
|
||||
files: ['**/*.svelte'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
parser: tseslint.parser,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'svelte/no-at-html-tags': 'error',
|
||||
'svelte/no-target-blank': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'off', // Allow any in Svelte files
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
4886
frontend/package-lock.json
generated
Normal file
4886
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,23 +20,26 @@
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"@types/node": "^22.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||
"@typescript-eslint/parser": "^7.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vitest/coverage-v8": "^2.0.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint": "^9.0.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-svelte": "^2.35.1",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-svelte": "^3.1.2",
|
||||
"svelte": "^4.2.0",
|
||||
"svelte-check": "^3.6.0",
|
||||
"svelte-eslint-parser": "^0.41.0",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.3.3",
|
||||
"typescript-eslint": "^8.0.0",
|
||||
"vite": "^5.0.3",
|
||||
"vitest": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"konva": "^9.3.0"
|
||||
"konva": "^9.3.0",
|
||||
"globals": "^15.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ export const handle: Handle = async ({ event, resolve }) => {
|
||||
const pathname = url.pathname;
|
||||
|
||||
// Check if route requires authentication
|
||||
const requiresAuth = protectedRoutes.some(route => pathname.startsWith(route));
|
||||
const requiresAuth = protectedRoutes.some((route) => pathname.startsWith(route));
|
||||
|
||||
if (requiresAuth) {
|
||||
// Check for auth token in cookies (or you could check localStorage via client-side)
|
||||
@@ -23,8 +23,8 @@ export const handle: Handle = async ({ event, resolve }) => {
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: {
|
||||
location: `/login?redirect=${encodeURIComponent(pathname)}`
|
||||
}
|
||||
location: `/login?redirect=${encodeURIComponent(pathname)}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -32,4 +32,3 @@ export const handle: Handle = async ({ event, resolve }) => {
|
||||
const response = await resolve(event);
|
||||
return response;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
import CreateBoardModal from '$lib/components/boards/CreateBoardModal.svelte';
|
||||
|
||||
let showCreateModal = false;
|
||||
let deleteConfirmId: string | null = null;
|
||||
|
||||
onMount(() => {
|
||||
boards.load();
|
||||
@@ -118,7 +117,9 @@
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
transition:
|
||||
transform 0.2s,
|
||||
box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
@@ -215,4 +216,3 @@
|
||||
gap: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
$: boardId = $page.params.id;
|
||||
|
||||
onMount(async () => {
|
||||
if (!boardId) {
|
||||
errors.general = 'Invalid board ID';
|
||||
isLoading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await boards.loadBoard(boardId);
|
||||
|
||||
@@ -45,7 +51,7 @@
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!validate()) return;
|
||||
if (!validate() || !boardId) return;
|
||||
|
||||
isSubmitting = true;
|
||||
|
||||
@@ -92,9 +98,7 @@
|
||||
<div class="error-banner">
|
||||
<span class="error-icon">⚠</span>
|
||||
{errors.general}
|
||||
<button class="back-btn-inline" on:click={() => goto('/boards')}>
|
||||
Return to Boards
|
||||
</button>
|
||||
<button class="back-btn-inline" on:click={() => goto('/boards')}> Return to Boards </button>
|
||||
</div>
|
||||
{:else}
|
||||
<form on:submit|preventDefault={handleSubmit} class="board-form">
|
||||
@@ -378,4 +382,3 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -81,7 +81,6 @@
|
||||
class:error={errors.title}
|
||||
maxlength="255"
|
||||
required
|
||||
autofocus
|
||||
/>
|
||||
{#if errors.title}
|
||||
<span class="error-text">{errors.title}</span>
|
||||
@@ -316,4 +315,3 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
onMount(() => {
|
||||
// Redirect if already authenticated
|
||||
authStore.subscribe(state => {
|
||||
authStore.subscribe((state) => {
|
||||
if (state.isAuthenticated) {
|
||||
goto('/boards');
|
||||
}
|
||||
@@ -39,7 +39,7 @@
|
||||
<div class="login-page">
|
||||
<div class="login-container">
|
||||
<h1>Login to Reference Board Viewer</h1>
|
||||
|
||||
|
||||
{#if error}
|
||||
<div class="error-message" role="alert">
|
||||
{error}
|
||||
@@ -111,4 +111,3 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
onMount(() => {
|
||||
// Redirect if already authenticated
|
||||
authStore.subscribe(state => {
|
||||
authStore.subscribe((state) => {
|
||||
if (state.isAuthenticated) {
|
||||
goto('/boards');
|
||||
}
|
||||
@@ -28,21 +28,24 @@
|
||||
try {
|
||||
await authApi.register({ email, password });
|
||||
success = 'Registration successful! Redirecting to login...';
|
||||
|
||||
|
||||
// Auto-login after successful registration
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
const response = await authApi.login({ email, password });
|
||||
authStore.login(response.user, response.access_token);
|
||||
goto('/boards');
|
||||
} catch (loginErr) {
|
||||
} catch {
|
||||
// If auto-login fails, just redirect to login page
|
||||
goto('/login');
|
||||
}
|
||||
}, 1500);
|
||||
} catch (err) {
|
||||
const apiError = err as ApiError;
|
||||
error = apiError.error || (apiError.details as any)?.detail || 'Registration failed. Please try again.';
|
||||
error =
|
||||
apiError.error ||
|
||||
(apiError.details as any)?.detail ||
|
||||
'Registration failed. Please try again.';
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
@@ -52,7 +55,7 @@
|
||||
<div class="register-page">
|
||||
<div class="register-container">
|
||||
<h1>Create Your Account</h1>
|
||||
|
||||
|
||||
{#if error}
|
||||
<div class="error-message" role="alert">
|
||||
{error}
|
||||
@@ -140,4 +143,3 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
22
frontend/svelte.config.js
Normal file
22
frontend/svelte.config.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import adapter from '@sveltejs/adapter-auto';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://svelte.dev/docs/kit/integrations
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
||||
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
||||
adapter: adapter(),
|
||||
alias: {
|
||||
$lib: 'src/lib',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
16
frontend/tsconfig.json
Normal file
16
frontend/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
},
|
||||
"exclude": ["tests/**/*", "node_modules/**/*", ".svelte-kit/**/*"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user