feat: add formidable ESLint + Prettier linting setup
Some checks failed
Build and Push Backend Image / build (push) Successful in 47s
Build and Push Frontend Image / build (push) Has been cancelled

- Root-level eslint.config.js (flat config): typescript-eslint,
  eslint-plugin-svelte, eslint-config-prettier, @eslint/js
- Root-level prettier.config.js with prettier-plugin-svelte
- svelte-check added to frontend for Svelte/TS type checking
- lint, lint:fix, format, format:check, check scripts in root
  and both packages
- All 60 lint errors fixed across backend and frontend:
  - Consistent type imports
  - Removed unused imports/variables
  - Added keys to all {#each} blocks for Svelte performance
  - Replaced mutable Set/Map with SvelteSet/SvelteMap
  - Fixed useless assignments and empty catch blocks
- 64 remaining warnings are intentional any usages in the
  Pothos/Drizzle GraphQL resolver layer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 22:24:55 +01:00
parent 741e0c3387
commit 18116072c9
43 changed files with 1023 additions and 5048 deletions

View File

@@ -56,7 +56,7 @@ function isActive() {
</div>
<div>
<h3
class={`font-semibold text-card-foreground group-hover:text-primary transition-colors`}
class="font-semibold text-card-foreground group-hover:text-primary transition-colors"
>
{device.name}
</h3>
@@ -139,7 +139,7 @@ function isActive() {
</div> -->
<!-- Action Button -->
{#each device.actuators as actuator, idx}
{#each device.actuators as actuator, idx (idx)}
<div class="space-y-2">
<Label for={`device-${device.info.index}-${actuator.featureIndex}-${actuator.outputType}`}
>{$_(

View File

@@ -1,6 +1,5 @@
<script lang="ts">
import { _ } from "svelte-i18n";
import PeonyIcon from "$lib/components/icon/peony-icon.svelte";
import Logo from "../logo/logo.svelte";
</script>

View File

@@ -1,12 +1,11 @@
<script lang="ts">
import { _ } from "svelte-i18n";
import { page } from "$app/state";
import PeonyIcon from "$lib/components/icon/peony-icon.svelte";
import { Button } from "$lib/components/ui/button";
import type { AuthStatus } from "$lib/types";
import { logout } from "$lib/services";
import { goto } from "$app/navigation";
import { getAssetUrl, isModel } from "$lib/directus";
import { getAssetUrl } from "$lib/directus";
import LogoutButton from "../logout-button/logout-button.svelte";
import Separator from "../ui/separator/separator.svelte";
import { Avatar, AvatarFallback, AvatarImage } from "$lib/components/ui/avatar";
@@ -64,7 +63,7 @@ function isActiveLink(link: any) {
<!-- Desktop Navigation -->
<nav class="hidden w-full lg:flex items-center justify-center gap-8">
{#each navLinks as link}
{#each navLinks as link (link.href)}
<a
href={link.href}
class={`text-sm hover:text-foreground transition-colors duration-200 font-medium relative group ${
@@ -219,7 +218,7 @@ function isActiveLink(link: any) {
{$_('header.navigation')}
</h3>
<div class="grid gap-2">
{#each navLinks as link}
{#each navLinks as link (link.href)}
<a
href={link.href}
class="flex items-center justify-between rounded-xl border border-border/50 bg-card/50 p-4 backdrop-blur-sm transition-all hover:bg-card hover:border-primary/20 {isActiveLink(
@@ -259,7 +258,7 @@ function isActiveLink(link: any) {
onclick={closeMenu}
>
<div
class={`flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-muted to-muted/50 transition-all group-hover:bg-card group-hover:from-primary/10 group-hover:to-accent/10`}
class="flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-muted to-muted/50 transition-all group-hover:bg-card group-hover:from-primary/10 group-hover:to-accent/10"
>
<span
class="icon-[ri--dashboard-2-line] h-4 w-4 text-muted-foreground group-hover:text-foreground transition-colors"
@@ -286,7 +285,7 @@ function isActiveLink(link: any) {
onclick={closeMenu}
>
<div
class={`flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-muted to-muted/50 transition-all group-hover:bg-card group-hover:from-primary/10 group-hover:to-accent/10`}
class="flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-muted to-muted/50 transition-all group-hover:bg-card group-hover:from-primary/10 group-hover:to-accent/10"
>
<span
class="icon-[ri--rocket-line] h-4 w-4 text-muted-foreground group-hover:text-foreground transition-colors"
@@ -313,7 +312,7 @@ function isActiveLink(link: any) {
onclick={closeMenu}
>
<div
class={`flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-muted to-muted/50 transition-all group-hover:bg-card group-hover:from-primary/10 group-hover:to-accent/10`}
class="flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-muted to-muted/50 transition-all group-hover:bg-card group-hover:from-primary/10 group-hover:to-accent/10"
>
<span
class="icon-[ri--login-circle-line] h-4 w-4 text-muted-foreground group-hover:text-foreground transition-colors"
@@ -340,7 +339,7 @@ function isActiveLink(link: any) {
onclick={closeMenu}
>
<div
class={`flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-muted to-muted/50 transition-all group-hover:bg-card group-hover:from-primary/10 group-hover:to-accent/10`}
class="flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-muted to-muted/50 transition-all group-hover:bg-card group-hover:from-primary/10 group-hover:to-accent/10"
>
<span
class="icon-[ri--heart-add-2-line] h-4 w-4 text-muted-foreground group-hover:text-foreground transition-colors"

View File

@@ -104,7 +104,7 @@ onDestroy(() => {
<div
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 animate-fade-in"
>
{#each images as image, index}
{#each images as image, index (index)}
<button
onclick={() => openViewer(index)}
class="group relative aspect-square overflow-hidden rounded-xl bg-zinc-900 border border-zinc-800 transition-all duration-300 hover:scale-[1.03] hover:border-primary/50 hover:shadow-2xl hover:shadow-primary/20 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 focus:ring-offset-zinc-950"

View File

@@ -94,7 +94,7 @@ function getStatusColor(status: string): string {
<!-- Device Info -->
<div class="space-y-1">
{#each recording.device_info.slice(0, 2) as device}
{#each recording.device_info.slice(0, 2) as device (device.name)}
<div
class="flex items-center gap-2 text-xs text-muted-foreground bg-muted/20 rounded px-2 py-1"
>
@@ -117,7 +117,7 @@ function getStatusColor(status: string): string {
<!-- Tags -->
{#if recording.tags && recording.tags.length > 0}
<div class="flex flex-wrap gap-1">
{#each recording.tags as tag}
{#each recording.tags as tag (tag)}
<span
class="text-xs px-2 py-0.5 rounded-full bg-primary/10 text-primary border border-primary/20"
>

View File

@@ -1,6 +1,4 @@
<script lang="ts">
import { Button } from "$lib/components/ui/button";
interface Props {
onclick: () => void;
icon: string;

View File

@@ -50,7 +50,7 @@ const copyLink = async () => {
try {
await navigator.clipboard.writeText(content.url);
toast.success($_("sharing_popup.success.copy"));
} catch (err) {
} catch {
// Fallback for older browsers
const textArea = document.createElement("textarea");
textArea.value = content.url;

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { Select as SelectPrimitive } from "bits-ui";
// eslint-disable-next-line no-useless-assignment
let { ref = $bindable(null), ...restProps }: SelectPrimitive.GroupProps =
$props();
</script>

View File

@@ -1,4 +1,4 @@
import { ButtplugClientDevice } from "@sexy.pivoine.art/buttplug";
import { type ButtplugClientDevice } from "@sexy.pivoine.art/buttplug";
export interface User {
id: string;

View File

@@ -1,4 +1,3 @@
import { browser } from "$app/environment";
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";