Skip to content

Commit de26f4c

Browse files
committed
Fix all lint errors: replace any types, fix unused vars, split statements
- Replace ~510 `no-explicit-any` errors with proper types across app, server, tests, and scripts - Prefix ~36 unused variables with _ (mostly destructured auth vars) - Split ~22 multi-statement lines - Remove 5 unnecessary escape characters - Add empty catch block comments - Auto-fix formatting (arrow parens, attribute newlines) - Add lint reminder to CLAUDE.md
1 parent 391d1f2 commit de26f4c

127 files changed

Lines changed: 3589 additions & 1484 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Demo: `demo@example.com` / `demo1234` | Admin: `admin@example.com` / `admin1234`
5757
- **DB access:** `db` + `schema` auto-imported. `server/utils/` is auto-imported — don't use `~/server/utils/...` (Nuxt 4: `~` = `app/`).
5858
- **Database schema:** `server/database/schema.ts` — all tables, columns, relations. Migrations in `server/database/migrations/`.
5959
- **OpenAPI spec** (`server/api/openapi.get.ts`) must stay in sync with endpoints. Only covers headless API usage — frontend-internal endpoints (slug/key validation, UI column config, notifications, OAuth redirects, registration flows) are intentionally omitted.
60-
- **Write tests** for new features. Run `pnpm test` after changes.
60+
- **Write tests** for new features. Run `pnpm test` and `pnpm lint` after changes.
6161

6262
### Don't
6363

app/components/AiWriteButton.vue

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ function handleCustomPrompt() {
4747
@mousedown.prevent
4848
@click="emit('cancel')"
4949
>
50-
<UIcon name="i-lucide-loader-2" class="text-[13px] animate-spin" />
50+
<UIcon
51+
name="i-lucide-loader-2"
52+
class="text-[13px] animate-spin"
53+
/>
5154
<span>Stop</span>
5255
</button>
5356

@@ -65,22 +68,31 @@ function handleCustomPrompt() {
6568
: 'text-white dark:text-white ring-0'"
6669
@mousedown.prevent
6770
>
68-
<UIcon name="i-lucide-sparkles" class="text-[13px]" />
71+
<UIcon
72+
name="i-lucide-sparkles"
73+
class="text-[13px]"
74+
/>
6975
<span>AI</span>
7076
</button>
7177

7278
<template #content>
7379
<div class="min-w-[220px] max-w-[280px]">
7480
<!-- Skills list -->
75-
<div v-if="(skills as any[])?.length" class="py-1">
81+
<div
82+
v-if="(skills as any[])?.length"
83+
class="py-1"
84+
>
7685
<button
7786
v-for="skill in (skills as any[])"
7887
:key="skill.id"
7988
type="button"
8089
class="w-full flex items-center gap-2 px-3 py-2 text-[13px] text-zinc-700 dark:text-zinc-200 hover:bg-zinc-50 dark:hover:bg-zinc-700/50 transition-colors text-left"
8190
@click="handleSkill(skill.id)"
8291
>
83-
<UIcon name="i-lucide-wand-sparkles" class="text-[14px] text-violet-500 shrink-0" />
92+
<UIcon
93+
name="i-lucide-wand-sparkles"
94+
class="text-[14px] text-violet-500 shrink-0"
95+
/>
8496
<span class="font-medium truncate">{{ skill.name }}</span>
8597
</button>
8698
</div>
@@ -101,14 +113,17 @@ function handleCustomPrompt() {
101113
class="flex-1 min-w-0 px-2.5 py-1.5 text-[13px] text-zinc-700 dark:text-zinc-200 placeholder-zinc-400 dark:placeholder-zinc-500 bg-zinc-50 dark:bg-zinc-700/50 border border-zinc-200 dark:border-zinc-600/50 rounded-lg outline-none focus:border-indigo-300 dark:focus:border-indigo-600 transition-colors"
102114
@keydown.enter.prevent="handleCustomPrompt"
103115
@keydown.stop
104-
/>
116+
>
105117
<button
106118
type="button"
107119
class="p-1.5 rounded-lg text-zinc-400 dark:text-zinc-500 hover:text-indigo-500 dark:hover:text-indigo-400 hover:bg-indigo-50 dark:hover:bg-indigo-950/30 transition-all disabled:opacity-30 disabled:cursor-not-allowed"
108120
:disabled="!customPrompt.trim()"
109121
@click="handleCustomPrompt"
110122
>
111-
<UIcon name="i-lucide-send" class="text-[14px]" />
123+
<UIcon
124+
name="i-lucide-send"
125+
class="text-[14px]"
126+
/>
112127
</button>
113128
</div>
114129
</div>

app/components/AttachmentList.vue

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ async function onFileInputChange(e: Event) {
1919
const files = input.files
2020
if (files?.length) {
2121
for (const file of files) {
22-
try { await upload(file) } catch {}
22+
try {
23+
await upload(file)
24+
} catch {
25+
// upload errors handled by composable
26+
}
2327
}
2428
}
2529
input.value = ''
@@ -36,7 +40,10 @@ let dropLeaveTimeout: ReturnType<typeof setTimeout> | null = null
3640
function onDropZoneDragEnter(e: DragEvent) {
3741
if (props.readonly || !e.dataTransfer?.types.includes('Files')) return
3842
e.preventDefault()
39-
if (dropLeaveTimeout) { clearTimeout(dropLeaveTimeout); dropLeaveTimeout = null }
43+
if (dropLeaveTimeout) {
44+
clearTimeout(dropLeaveTimeout)
45+
dropLeaveTimeout = null
46+
}
4047
dropActive.value = true
4148
}
4249
@@ -47,7 +54,9 @@ function onDropZoneDragOver(e: DragEvent) {
4754
4855
function onDropZoneDragLeave() {
4956
if (dropLeaveTimeout) clearTimeout(dropLeaveTimeout)
50-
dropLeaveTimeout = setTimeout(() => { dropActive.value = false }, 50)
57+
dropLeaveTimeout = setTimeout(() => {
58+
dropActive.value = false
59+
}, 50)
5160
}
5261
5362
async function onDropZoneDrop(e: DragEvent) {
@@ -57,7 +66,11 @@ async function onDropZoneDrop(e: DragEvent) {
5766
const files = e.dataTransfer?.files
5867
if (!files?.length) return
5968
for (const file of files) {
60-
try { await upload(file) } catch {}
69+
try {
70+
await upload(file)
71+
} catch {
72+
// upload errors handled by composable
73+
}
6174
}
6275
}
6376
@@ -72,11 +85,14 @@ defineExpose({ upload, uploading })
7285
multiple
7386
class="hidden"
7487
@change="onFileInputChange"
75-
/>
88+
>
7689

7790
<!-- Header -->
7891
<div class="flex items-center gap-1.5 mb-2">
79-
<UIcon name="i-lucide-paperclip" class="text-[13px] text-zinc-400 dark:text-zinc-500" />
92+
<UIcon
93+
name="i-lucide-paperclip"
94+
class="text-[13px] text-zinc-400 dark:text-zinc-500"
95+
/>
8096
<span class="text-[12px] font-semibold uppercase tracking-[0.04em] text-zinc-400 dark:text-zinc-500">Attachments</span>
8197
<span
8298
v-if="attachments.length"
@@ -91,12 +107,18 @@ defineExpose({ upload, uploading })
91107
v-if="uploading"
92108
class="flex items-center gap-2 px-3 py-2 rounded-lg border border-dashed border-indigo-300 dark:border-indigo-700 bg-indigo-50/50 dark:bg-indigo-950/20 mb-2"
93109
>
94-
<UIcon name="i-lucide-loader-2" class="text-[14px] text-indigo-500 animate-spin" />
110+
<UIcon
111+
name="i-lucide-loader-2"
112+
class="text-[14px] text-indigo-500 animate-spin"
113+
/>
95114
<span class="text-[12px] font-medium text-indigo-500">Uploading...</span>
96115
</div>
97116

98117
<!-- Attachment list -->
99-
<div v-if="attachments.length" class="rounded-lg border border-zinc-200 dark:border-zinc-700/60 bg-white dark:bg-zinc-800/50 divide-y divide-zinc-100 dark:divide-zinc-700/40">
118+
<div
119+
v-if="attachments.length"
120+
class="rounded-lg border border-zinc-200 dark:border-zinc-700/60 bg-white dark:bg-zinc-800/50 divide-y divide-zinc-100 dark:divide-zinc-700/40"
121+
>
100122
<div
101123
v-for="attachment in attachments"
102124
:key="attachment.id"
@@ -109,7 +131,7 @@ defineExpose({ upload, uploading })
109131
:src="downloadUrl(attachment.id)"
110132
:alt="attachment.originalName"
111133
class="w-full h-full object-cover"
112-
/>
134+
>
113135
<UIcon
114136
v-else
115137
:name="fileIcon(attachment.mimeType)"
@@ -133,22 +155,31 @@ defineExpose({ upload, uploading })
133155
</div>
134156

135157
<!-- Actions -->
136-
<div v-if="!readonly" class="flex items-center gap-1 shrink-0">
158+
<div
159+
v-if="!readonly"
160+
class="flex items-center gap-1 shrink-0"
161+
>
137162
<a
138163
:href="downloadUrl(attachment.id)"
139164
target="_blank"
140165
class="p-1 rounded-md text-zinc-400 dark:text-zinc-500 hover:text-zinc-600 dark:hover:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-zinc-700/50 opacity-0 sm:group-hover:opacity-100 max-sm:opacity-60 transition-all"
141166
title="Download"
142167
>
143-
<UIcon name="i-lucide-download" class="text-[13px]" />
168+
<UIcon
169+
name="i-lucide-download"
170+
class="text-[13px]"
171+
/>
144172
</a>
145173
<button
146174
type="button"
147175
class="p-1 rounded-md text-zinc-400 dark:text-zinc-500 hover:text-red-500 dark:hover:text-red-400 hover:bg-red-50 dark:hover:bg-red-950/20 opacity-0 sm:group-hover:opacity-100 max-sm:opacity-60 transition-all"
148176
title="Remove"
149177
@click="remove(attachment.id)"
150178
>
151-
<UIcon name="i-lucide-trash-2" class="text-[13px]" />
179+
<UIcon
180+
name="i-lucide-trash-2"
181+
class="text-[13px]"
182+
/>
152183
</button>
153184
</div>
154185
</div>

app/components/AuthErrorBanner.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ defineProps<{
99
v-if="error"
1010
class="auth-field flex items-center gap-2 text-[13px] text-red-600 dark:text-red-400 bg-red-50/80 dark:bg-red-950/30 rounded-lg px-3 py-2.5 backdrop-blur-sm border border-red-200/50 dark:border-red-800/30"
1111
>
12-
<UIcon name="i-lucide-alert-circle" class="shrink-0" />
12+
<UIcon
13+
name="i-lucide-alert-circle"
14+
class="shrink-0"
15+
/>
1316
{{ error }}
1417
</div>
1518
</template>

0 commit comments

Comments
 (0)