This commit is contained in:
Danilo Reyes
2025-11-02 01:47:25 -06:00
parent 48020b6f42
commit 010df31455
45 changed files with 8045 additions and 720 deletions

View File

@@ -1,11 +0,0 @@
node_modules/
dist/
build/
.svelte-kit/
coverage/
*.min.js
package-lock.json
pnpm-lock.yaml
yarn.lock
.DS_Store

View File

@@ -48,4 +48,3 @@ module.exports = {
'svelte/no-target-blank': 'error'
}
};

63
frontend/eslint.config.js Normal file
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -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"
}
}

View File

@@ -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;
};

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
View 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
View 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/**/*"]
}