Refactor imports to use new aliasing convention and update environment variable handling

- Changed imports from '$lib' to '#lib' for consistency across the codebase.
- Updated environment variable imports to use the new structure from '$app/env/public' and '$app/env/private'.
- Removed deprecated svelte.config.js and adjusted vite.config.js to accommodate new configurations.
- Added stubs for environment variables in tests to ensure compatibility with the new import structure.
This commit is contained in:
Ashwin 2026-10-15 20:38:58 +05:30
parent 8eb68b5431
commit f6e453098b
548 changed files with 3430 additions and 3375 deletions

View file

@ -5,7 +5,7 @@ A free, self-hosted, multi-tenant CRM built with Django REST Framework, SvelteKi
![License](https://img.shields.io/badge/license-MIT-blue.svg)
![Python](https://img.shields.io/badge/python-3.12+-green.svg)
![Django](https://img.shields.io/badge/django-6.x-green.svg)
![SvelteKit](https://img.shields.io/badge/sveltekit-2.x-orange.svg)
![SvelteKit](https://img.shields.io/badge/sveltekit-3.x-orange.svg)
![Svelte](https://img.shields.io/badge/svelte-5-orange.svg)
![Flutter](https://img.shields.io/badge/flutter-3.44+-blue.svg)
![Coverage](./coverage-badge.svg)

View file

@ -29,7 +29,7 @@ Minimum versions, as declared in `pyproject.toml`. That file is the source of
truth; the list here is a summary and `uv.lock` pins what actually gets
installed.
- **Django 6.1.1+** - Web framework
- **Django 6.1.2+** - Web framework
- **Django REST Framework 3.17+** - API toolkit
- **PostgreSQL** - Database, via **psycopg 3.2.10+** with the `pool` extra
- **Celery 5.6+** - Async task queue

View file

@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "django-crm"
version = "1.16.0"
version = "1.17.0"
# The one-line summary PyPI shows under the project title and in search results,
# so it carries the terms people actually search for ("open source CRM",
# "self-hosted CRM", "Django CRM") and names the modules rather than the
@ -59,14 +59,14 @@ classifiers = [
]
dependencies = [
"django>=6.1.1",
"django>=6.1.2",
"celery>=5.6.3",
"python-dotenv>=1.2.3",
"python-dotenv>=1.2.4",
"django-cors-headers>=4.9.0",
"djangorestframework>=3.18.1",
"djangorestframework>=3.18.3",
"djangorestframework-simplejwt>=5.5.1",
"drf-spectacular>=0.30.0",
"django-ses>=4.8.0",
"django-ses>=4.8.2",
# psycopg 3, not psycopg2. The `pool` extra is required: Django refuses
# pool options under psycopg2 (ImproperlyConfigured, "Database pooling
# requires psycopg >= 3"), and DATABASES["default"]["OPTIONS"]["pool"] in
@ -74,21 +74,21 @@ dependencies = [
# directly, so the swap is confined to this line.
"psycopg[binary,pool]>=3.3.6",
"whitenoise>=6.12.0",
"sentry-sdk>=2.70.0",
"sentry-sdk>=2.72.0",
"django-storages>=1.14.6",
"django-crum>=0.7.9",
"disposable-email-domains>=0.0.268",
"disposable-email-domains>=0.0.280",
"redis>=8.1.0",
"pytz>=2026.4",
"pytz>=2026.5",
"requests>=2.34.2",
"faker>=40.39.0",
"faker>=40.43.0",
"python-dateutil>=2.9.0.post0",
"google-auth>=2.58.1",
"google-auth>=2.62.0",
# X.509 handling for inbound SNS webhook signature verification
# (cases/inbound/sns.py). The API floor is 42, where the not_valid_*_utc
# accessors landed; this pin sits higher only because floors here track the
# versions in uv.lock.
"cryptography>=50.0.1",
"cryptography>=50.0.2",
# Routing-rule `regex` conditions (cases/routing.py). RE2 matches in time
# linear in the input, so an admin's pattern cannot backtrack for hours on
# a ticket's tags or sender domain the way `re` can.
@ -118,7 +118,7 @@ dev = [
"pytest>=9.1.1",
"pytest-django>=4.14.0",
"pytest-cov>=7.1.0",
"ruff>=0.16.9",
"ruff>=0.17.0",
]
docs = [
"mkdocs-material>=9.7.7",

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,7 @@ them.
| Component | Version | Source |
|---|---|---|
| Python | 3.12 or later | `backend/pyproject.toml` sets `requires-python = ">=3.12"`; `backend/.python-version` pins `3.12` exactly. |
| Django | 6.1.1 or later | `backend/pyproject.toml` dependency `django>=6.1.1`. |
| Django | 6.1.2 or later | `backend/pyproject.toml` dependency `django>=6.1.2`. |
| PostgreSQL | 16 | `docker-compose.yml`'s `db` service uses image `postgres:16-alpine`. This is also the only version this project's own CI ever runs against. See the note below. |
| Redis | 7 | `docker-compose.yml`'s `redis` service uses image `redis:7-alpine`. |
| Node.js | 24 | `.github/workflows/tests.yml`'s `frontend-checks` job sets up `node-version: '24'`. |

View file

@ -7,21 +7,25 @@
#
# RUNTIME CONFIGURATION
#
# Every value this app reads from the environment comes through
# `$env/dynamic/public`, which adapter-node resolves per process at startup, not
# at build time. So one image serves any deployment and nothing below bakes a
# hostname in:
# Every value this app reads from the environment is declared in src/env.js and
# read per process at startup, not at build time. So one image serves any
# deployment and nothing below bakes a hostname in:
#
# PUBLIC_DJANGO_API_URL required. The Django API origin, no trailing /api.
# ORIGIN required in production. See below.
# PUBLIC_SENTRY_DSN optional. Unset disables Sentry (`enabled: !!dsn`).
# PORT defaults to 3000. HOST already defaults to 0.0.0.0.
# PROTOCOL_HEADER only for plain http. See below.
#
# ORIGIN is the one that fails quietly. adapter-node compares the Origin header
# of every form POST against it, and with no ORIGIN set a proxied request is
# answered `403 Cross-site POST form submissions are forbidden`. GETs still
# work, so the app looks healthy while all 64 form actions reject. Set it to the
# public URL users type, e.g. ORIGIN=https://crm.example.com.
# The origin check is the one that fails quietly. SvelteKit compares the Origin
# header of every form POST with the origin the server thinks it serves, which
# adapter-node 6 builds from the request's Host header and the scheme `https`.
# (The ORIGIN variable that used to override this was removed in SvelteKit 3,
# so setting it does nothing.) Behind a TLS proxy that forwards Host, such as
# nginx with `proxy_set_header Host $host`, that is already right. If users
# reach the app over plain http, set PROTOCOL_HEADER=x-forwarded-proto and have
# the proxy send that header. Otherwise every form POST is answered `403
# Cross-site POST form submissions are forbidden` while GETs still work, so the
# app looks healthy while all its form actions reject.
FROM node:24-slim AS base
# Pinned so image builds are reproducible.

View file

@ -10,7 +10,7 @@ BottleCRM is a free, open-source Customer Relationship Management solution desig
- **Multi-Tenant Architecture**: Secure organization-based data isolation
- **Role-Based Access Control**: Granular permissions for users and admins
- **Modern Technology Stack**: Built with SvelteKit 2.x, Svelte 5.x, and PostgreSQL
- **Modern Technology Stack**: Built with SvelteKit 3.x, Svelte 5.x, and PostgreSQL
- **Mobile-First Design**: Responsive interface optimized for all devices
## 🚀 Core Features
@ -57,7 +57,7 @@ BottleCRM is a free, open-source Customer Relationship Management solution desig
## 🖥️ Technology Stack
- **Frontend**: SvelteKit 2.x, Svelte 5.x, TailwindCSS 4.x
- **Frontend**: SvelteKit 3.x, Svelte 5.x, TailwindCSS 4.x
- **Backend**: Node.js with Prisma ORM
- **Database**: PostgreSQL (recommended) with multi-tenant schema
- **Authentication**: Session-based authentication with organization membership

View file

@ -4,7 +4,6 @@ import { includeIgnoreFile } from '@eslint/compat';
import svelte from 'eslint-plugin-svelte';
import globals from 'globals';
import { fileURLToPath } from 'node:url';
import svelteConfig from './svelte.config.js';
const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
@ -19,10 +18,6 @@ export default [
globals: { ...globals.browser, ...globals.node }
}
},
{
files: ['**/*.svelte', '**/*.svelte.js'],
languageOptions: { parserOptions: { svelteConfig } }
},
{
rules: {
'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],

View file

@ -1,22 +1,11 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"extends": "$app/tsconfig",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"noImplicitAny": false,
"useUnknownInCatchVariables": false,
"strictNullChecks": false,
"moduleResolution": "bundler"
}
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
"strictNullChecks": false
},
"include": ["src", "vite.config.js", "test"]
}

View file

@ -19,38 +19,42 @@
"@eslint/compat": "^2.1.1",
"@eslint/js": "^10.0.1",
"@internationalized/date": "^3.12.4",
"@lucide/svelte": "^1.48.0",
"@sveltejs/adapter-node": "^5.5.7",
"@sveltejs/kit": "^2.70.3",
"@lucide/svelte": "^1.57.0",
"@sveltejs/adapter-node": "^6.0.0",
"@sveltejs/kit": "^3.0.1",
"@sveltejs/vite-plugin-svelte": "^7.3.1",
"@tailwindcss/typography": "^0.5.20",
"@tailwindcss/vite": "^4.3.3",
"@types/node": "^26.6.2",
"bits-ui": "^2.19.3",
"eslint": "^10.11.0",
"@types/node": "^26.6.5",
"bits-ui": "^2.19.5",
"eslint": "^10.12.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.23.0",
"globals": "^17.12.0",
"eslint-plugin-svelte": "^3.23.1",
"globals": "^17.13.0",
"mode-watcher": "^1.1.0",
"prettier": "^3.9.9",
"prettier": "^3.9.10",
"prettier-plugin-svelte": "^4.1.1",
"prettier-plugin-tailwindcss": "^0.8.1",
"svelte": "^5.57.1",
"svelte": "^5.57.2",
"svelte-check": "^4.7.6",
"svelte-sonner": "^1.2.1",
"tailwindcss": "^4.3.3",
"typescript": "^6.0.3",
"vite": "^8.3.1",
"vitest": "^5.0.2"
"vite": "^8.3.4",
"vitest": "^5.0.4"
},
"dependencies": {
"@sentry/sveltekit": "^11.0.0",
"@sentry/sveltekit": "^11.7.0",
"axios": "^1.20.0",
"clsx": "^2.1.1",
"libphonenumber-js": "^1.13.14",
"svelte-dnd-action": "^0.9.79",
"libphonenumber-js": "^1.13.15",
"svelte-dnd-action": "^0.9.80",
"tailwind-merge": "^3.7.0",
"tailwind-variants": "^3.3.1",
"tw-animate-css": "^1.4.0"
},
"imports": {
"#lib": "./src/lib/index.js",
"#lib/*": "./src/lib/*"
}
}

File diff suppressed because it is too large Load diff

View file

@ -7,9 +7,8 @@ overrides:
# Only reachable through dev tooling (eslint, @sentry/vite-plugin), but the
# transitive parents still ask for a vulnerable range, so force the patch.
'brace-expansion@>=4.0.0 <5.0.9': '^5.0.9'
# GHSA-pxg6-pf52-xh8x (low): cookie name/path/domain accept out-of-bounds
# characters. Reachable at runtime, not just in dev tooling: @sveltejs/kit
# parses and serialises the jwt_access / jwt_refresh / org cookies through
# this package. Kit still asks for ^0.6.0, so force the patched line. Kit
# only calls parse() and serialize(), both unchanged in 0.7.
'cookie@<0.7.0': '^0.7.2'
# GHSA-rj75-hqrm-r3gf (moderate): quadratic parsing of flat selectors.
# Build-time only: @tailwindcss/typography 0.5.20 pins 6.0.10 exactly. 7.0's
# one breaking change makes insertion during iteration safe; typography only
# removes nodes from a copied array, and the built CSS is byte-identical.
'postcss-selector-parser@<7.1.6': '^7.1.6'

33
frontend/src/env.js Normal file
View file

@ -0,0 +1,33 @@
import { defineEnvVars } from '@sveltejs/kit/env';
/**
* Every environment variable the app reads. SvelteKit 3 exposes only what is
* declared here, through `$app/env/public` and `$app/env/private`.
*
* None is `static`, so each is read when the server starts rather than baked
* in at build time: one Docker image serves any deployment. Each schema passes
* the raw value through, so an unset variable is `undefined`, which is what
* every caller already handles.
*/
/** @param {string | undefined} value */
const optional = (value) => value;
export const variables = defineEnvVars({
PUBLIC_DJANGO_API_URL: {
public: true,
schema: optional,
description: 'The Django API origin, without a trailing /api.'
},
PUBLIC_SENTRY_DSN: {
public: true,
schema: optional,
description: 'Sentry DSN. Unset disables Sentry.'
},
RELAY_SECRET: {
schema: optional,
description: "Shared with the API's RELAY_SECRET so it believes the relayed visitor address."
},
GOOGLE_CLIENT_ID: { schema: optional },
GOOGLE_LOGIN_DOMAIN: { schema: optional },
NODE_ENV: { schema: optional }
});

View file

@ -1,6 +1,6 @@
import { handleErrorWithSentry, replayIntegration } from '@sentry/sveltekit';
import * as Sentry from '@sentry/sveltekit';
import { env } from '$env/dynamic/public';
import * as env from '$app/env/public';
const dsn = env.PUBLIC_SENTRY_DSN || '';

View file

@ -12,10 +12,10 @@ import * as Sentry from '@sentry/sveltekit';
import { redirect } from '@sveltejs/kit';
import axios from 'axios';
import { env } from '$env/dynamic/public';
import { isOrgAdmin } from '$lib/admin.js';
import { describeError } from '$lib/server/log-safe.js';
import { relayHeaders } from '$lib/server/relay.js';
import * as env from '$app/env/public';
import { isOrgAdmin } from '#lib/admin.js';
import { describeError } from '#lib/server/log-safe.js';
import { relayHeaders } from '#lib/server/relay.js';
const API_BASE_URL = `${env.PUBLIC_DJANGO_API_URL}/api`;
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@ -120,7 +120,7 @@ function refreshAccessToken(refreshToken, event) {
* It deduplicates concurrent callers.
*
* The API writes an audit row for every refresh, so the visitor's signed
* address goes along (`$lib/server/relay.js`); without it the row records
* address goes along (`#lib/server/relay.js`); without it the row records
* this server.
*
* @param {string} refreshToken - JWT refresh token
@ -160,7 +160,7 @@ async function performTokenRefresh(refreshToken, event) {
* @param {string} orgId - Organization UUID to switch to
* @param {string | undefined} refreshToken - Refresh token being replaced, to be retired
* @param {{ getClientAddress: () => string, request: Request }} event - For the visitor's address,
* which the API's org-switch audit row records (`$lib/server/relay.js`)
* which the API's org-switch audit row records (`#lib/server/relay.js`)
* @returns {Promise<SwitchOrgResult|null>} New tokens and org data or null if failed
*/
async function switchOrg(accessToken, orgId, refreshToken, event) {
@ -265,7 +265,7 @@ export const handle = sequence(Sentry.sentryHandle(), async function _handle({ e
/** @type {any} */ (event.locals).profile = {
org: event.locals.org,
role: jwtPayload.role || 'USER',
// The admin fact every admin gate reads (`$lib/admin.js`). Server
// The admin fact every admin gate reads (`#lib/admin.js`). Server
// derived and signed; `role` stays for display only.
is_organization_admin: isOrgAdmin(jwtPayload)
};

View file

@ -1,6 +1,6 @@
/**
* The shell's token refresh and org switch send the visitor's signed address
* (`$lib/server/relay.js`): the API writes an audit row for each, and without
* (`#lib/server/relay.js`): the API writes an audit row for each, and without
* it the row records this server.
*/
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
@ -20,7 +20,9 @@ vi.mock('@sveltejs/kit/hooks', () => ({
vi.mock('axios', () => ({ default: { post: vi.fn(), get: vi.fn() } }));
const axios = (await import('axios')).default;
const { env: privateEnv } = await import('$env/dynamic/private');
// The stub that vitest.config.js aliases `$app/env/private` to, so this is the module the code
// under test reads. Imported by path because only the stub has a setter.
const { setRelaySecret } = await import('../test/stubs/app-env-private.js');
const { handle } = await import('./hooks.server.js');
const SECRET = 'r'.repeat(48);
@ -62,12 +64,12 @@ const callTo = (path) =>
vi.mocked(axios.post).mock.calls.find(([url]) => String(url).endsWith(path));
beforeEach(() => {
privateEnv.RELAY_SECRET = SECRET;
setRelaySecret(SECRET);
vi.mocked(axios.post).mockReset();
});
afterEach(() => {
delete privateEnv.RELAY_SECRET;
setRelaySecret(undefined);
});
describe('hooks.server.js relays the visitor', () => {
@ -110,7 +112,7 @@ describe('hooks.server.js relays the visitor', () => {
});
it('sends only the pre-1.12 X-Forwarded-For without a secret', async () => {
delete privateEnv.RELAY_SECRET;
setRelaySecret(undefined);
vi.mocked(axios.post).mockResolvedValue({ data: {} });
await handle({

View file

@ -1,5 +1,5 @@
import * as Sentry from '@sentry/sveltekit';
import { env } from '$env/dynamic/public';
import * as env from '$app/env/public';
const dsn = env.PUBLIC_SENTRY_DSN || '';

View file

@ -5,7 +5,7 @@
* Used by SvelteKit server files during migration from Prisma to API.
*/
import { env } from '$env/dynamic/public';
import * as env from '$app/env/public';
const API_BASE_URL = `${env.PUBLIC_DJANGO_API_URL}/api`;

View file

@ -8,7 +8,7 @@ import { resolve } from '$app/paths';
* @module lib/api
*/
import { env } from '$env/dynamic/public';
import * as env from '$app/env/public';
import { goto } from '$app/navigation';
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@ -177,7 +177,7 @@ async function performTokenRefresh() {
// Refresh token expired or invalid
clearAuthData();
if (typeof window !== 'undefined') {
goto(resolve('/login'));
goto(resolve('login'));
}
return null;
} catch (error) {
@ -318,7 +318,7 @@ export const auth = {
logout() {
clearAuthData();
if (typeof window !== 'undefined') {
goto(resolve('/login'));
goto(resolve('login'));
}
}
};

View file

@ -1,8 +1,8 @@
<script>
import { resolve } from '$app/paths';
import { asInternalPath } from '$lib/utils/paths.js';
import { asInternalPath } from '#lib/utils/paths.js';
import { goto } from '$app/navigation';
import { Button } from '$lib/components/ui/button/index.js';
import { Button } from '#lib/components/ui/button/index.js';
import { ArrowLeft, Home, Compass, Users, FileText, Ticket, BarChart3 } from '@lucide/svelte';
/**
@ -46,7 +46,7 @@
function goBack() {
if (typeof history !== 'undefined' && history.length > 1) history.back();
else goto(resolve('/'));
else goto(resolve(''));
}
</script>
@ -78,7 +78,7 @@
<!-- Primary actions -->
<div class="flex flex-col items-center justify-center gap-3 sm:flex-row">
<Button onclick={() => goto(resolve('/'))} class="gap-2">
<Button onclick={() => goto(resolve(''))} class="gap-2">
<Home class="h-4 w-4" />
Go to dashboard
</Button>

View file

@ -1,10 +1,10 @@
<script>
import { invalidateAll } from '$app/navigation';
import { refreshAll } from '$app/navigation';
import { deserialize } from '$app/forms';
import { Loader2, Upload, FileText, Download, CheckCircle2, AlertCircle } from '@lucide/svelte';
import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js';
import { downloadImportErrors } from '$lib/utils/csv.js';
import { Button } from '#lib/components/ui/button/index.js';
import * as Dialog from '#lib/components/ui/dialog/index.js';
import { downloadImportErrors } from '#lib/utils/csv.js';
/**
* Two-step CSV import flow: upload → preview → confirm.
@ -194,7 +194,7 @@
if (result.type === 'success' && result.data?.importCommit) {
commitResult = result.data.importCommit;
step = 'done';
await invalidateAll();
await refreshAll();
}
} catch (err) {
formError = err instanceof Error ? err.message : 'Import failed';

View file

@ -1,12 +1,12 @@
<script>
import { resolve } from '$app/paths';
import { enhance } from '$app/forms';
import { invalidateAll } from '$app/navigation';
import { refreshAll } from '$app/navigation';
import { toast } from 'svelte-sonner';
import { Sliders, Loader2, Check } from '@lucide/svelte';
import { Button } from '$lib/components/ui/button/index.js';
import { Input } from '$lib/components/ui/input/index.js';
import { Label } from '$lib/components/ui/label/index.js';
import { Button } from '#lib/components/ui/button/index.js';
import { Input } from '#lib/components/ui/input/index.js';
import { Label } from '#lib/components/ui/label/index.js';
/**
* @typedef {Object} CustomFieldDef
@ -80,7 +80,7 @@
{#if isEmpty}
<p class="text-sm text-[var(--text-secondary)]">
No custom fields configured for {target.toLowerCase()}.
<a class="underline" href={resolve(`/settings/custom-fields?target=${target}`)}>Manage</a>
<a class="underline" href={resolve(`settings/custom-fields?target=${target}`)}>Manage</a>
</p>
{:else}
<form
@ -93,7 +93,7 @@
saving = false;
if (result.type === 'success') {
toast.success(`${title} saved`);
await invalidateAll();
await refreshAll();
} else if (result.type === 'failure') {
toast.error(String(result.data?.error || 'Failed to save'));
}

View file

@ -1,6 +1,6 @@
<script>
import { SvelteDate } from 'svelte/reactivity';
import { Button } from '$lib/components/ui/button/index.js';
import { Button } from '#lib/components/ui/button/index.js';
import {
Activity,
Plus,

View file

@ -1,6 +1,6 @@
<script>
import { resolve } from '$app/paths';
import { asInternalPath } from '$lib/utils/paths.js';
import { asInternalPath } from '#lib/utils/paths.js';
import { AlertCircle, Calendar, Phone, Flame, Zap } from '@lucide/svelte';
/**

View file

@ -1,8 +1,8 @@
<script>
import { SvelteDate } from 'svelte/reactivity';
import { resolve } from '$app/paths';
import { Badge } from '$lib/components/ui/badge/index.js';
import { Button } from '$lib/components/ui/button/index.js';
import { Badge } from '#lib/components/ui/badge/index.js';
import { Button } from '#lib/components/ui/button/index.js';
import { Flame, Phone, Mail, ChevronRight, Calendar, Sparkles } from '@lucide/svelte';
/**
@ -131,7 +131,7 @@
{#each leads as lead (lead.id)}
{@const config = ratingConfig[lead.rating || 'HOT'] || ratingConfig.HOT}
<a
href={resolve(`/leads?view=${lead.id}`)}
href={resolve(`leads?view=${lead.id}`)}
class="group flex items-center gap-3 px-5 py-3 transition-all duration-200 hover:bg-[var(--color-primary-light)] dark:hover:bg-[var(--color-primary-default)]/5"
>
<!-- Lead info -->

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
import { TrendingUp, TrendingDown } from '@lucide/svelte';
/**

View file

@ -1,8 +1,8 @@
<script>
import { SvelteDate } from 'svelte/reactivity';
import { resolve } from '$app/paths';
import { Badge } from '$lib/components/ui/badge/index.js';
import { Button } from '$lib/components/ui/button/index.js';
import { Badge } from '#lib/components/ui/badge/index.js';
import { Button } from '#lib/components/ui/button/index.js';
import { Circle, CheckCircle2, ChevronRight, ListTodo } from '@lucide/svelte';
/**
@ -199,7 +199,7 @@
{#each filteredTasks() as task (task.id)}
{@const config = getPriorityConfig(task.priority)}
<a
href={resolve(`/tasks?view=${task.id}`)}
href={resolve(`tasks?view=${task.id}`)}
class="group flex items-center gap-3 px-5 py-3 transition-all duration-200 hover:bg-[var(--color-primary-light)] dark:hover:bg-[var(--color-primary-default)]/5"
>
<!-- Status icon -->

View file

@ -1,5 +1,5 @@
<script>
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
import * as Sidebar from '#lib/components/ui/sidebar/index.js';
import AppSidebar from './AppSidebar.svelte';
/**

View file

@ -1,14 +1,14 @@
<script>
import { resolve } from '$app/paths';
import { asInternalPath } from '$lib/utils/paths.js';
import { asInternalPath } from '#lib/utils/paths.js';
import { untrack } from 'svelte';
import { page } from '$app/stores';
import { page } from '$app/state';
import { afterNavigate, goto } from '$app/navigation';
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index.js';
import * as Collapsible from '$lib/components/ui/collapsible/index.js';
import { Avatar, AvatarFallback } from '$lib/components/ui/avatar/index.js';
import * as Sidebar from '#lib/components/ui/sidebar/index.js';
import * as DropdownMenu from '#lib/components/ui/dropdown-menu/index.js';
import * as Collapsible from '#lib/components/ui/collapsible/index.js';
import { Avatar, AvatarFallback } from '#lib/components/ui/avatar/index.js';
import {
Target,
@ -50,7 +50,7 @@
Smartphone,
KeyRound
} from '@lucide/svelte';
import { Bell } from '$lib/components/notifications/index.js';
import { Bell } from '#lib/components/notifications/index.js';
/**
* @typedef {Object} Props
@ -125,7 +125,7 @@
localStorage.setItem('theme', newTheme);
};
let currentPath = $derived($page.url.pathname);
let currentPath = $derived(page.url.pathname);
/** @type {{ [key: string]: boolean }} */
let openDropdowns = $state({});
@ -380,7 +380,7 @@
>
<div class="flex items-center gap-2">
<a
href={resolve('/org')}
href={resolve('org')}
data-sveltekit-preload-data="off"
class="flex min-w-0 flex-1 items-center gap-2.5 rounded-md px-1 py-1 transition-colors hover:bg-[color:var(--sidebar-accent)] focus-visible:ring-2 focus-visible:ring-[color:var(--sidebar-ring)] focus-visible:outline-none"
>

View file

@ -1,8 +1,8 @@
<script>
import { Filter } from '@lucide/svelte';
import { Button } from '$lib/components/ui/button/index.js';
import { Badge } from '$lib/components/ui/badge/index.js';
import * as Popover from '$lib/components/ui/popover/index.js';
import { Button } from '#lib/components/ui/button/index.js';
import { Badge } from '#lib/components/ui/badge/index.js';
import * as Popover from '#lib/components/ui/popover/index.js';
/**
* @type {{

View file

@ -1,6 +1,6 @@
<script>
import { resolve } from '$app/paths';
import { asInternalPath } from '$lib/utils/paths.js';
import { asInternalPath } from '#lib/utils/paths.js';
import { ChevronRight } from '@lucide/svelte';
/**

View file

@ -1,10 +1,10 @@
<script>
import { invalidateAll } from '$app/navigation';
import { refreshAll } from '$app/navigation';
import { deserialize } from '$app/forms';
import { Loader2, Upload, FileText, Download, CheckCircle2, AlertCircle } from '@lucide/svelte';
import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js';
import { downloadImportErrors } from '$lib/utils/csv.js';
import { Button } from '#lib/components/ui/button/index.js';
import * as Dialog from '#lib/components/ui/dialog/index.js';
import { downloadImportErrors } from '#lib/utils/csv.js';
/**
* Two-step CSV import flow: upload → preview → confirm.
@ -190,7 +190,7 @@
if (result.type === 'success' && result.data?.importCommit) {
commitResult = result.data.importCommit;
step = 'done';
await invalidateAll();
await refreshAll();
}
} catch (err) {
formError = err instanceof Error ? err.message : 'Import failed';

View file

@ -1,8 +1,8 @@
<script>
import { Bell as BellIcon } from '@lucide/svelte';
import * as Popover from '$lib/components/ui/popover/index.js';
import { Button } from '$lib/components/ui/button/index.js';
import { notifications } from '$lib/stores/notifications.svelte.js';
import * as Popover from '#lib/components/ui/popover/index.js';
import { Button } from '#lib/components/ui/button/index.js';
import { notifications } from '#lib/stores/notifications.svelte.js';
import NotificationPanel from './NotificationPanel.svelte';
let open = $state(false);

View file

@ -11,8 +11,8 @@
Trash2,
UserPlus
} from '@lucide/svelte';
import { formatRelativeDate } from '$lib/utils/formatting.js';
import { notifications } from '$lib/stores/notifications.svelte.js';
import { formatRelativeDate } from '#lib/utils/formatting.js';
import { notifications } from '#lib/stores/notifications.svelte.js';
/**
* @type {{

View file

@ -1,10 +1,10 @@
<script>
import { invalidateAll } from '$app/navigation';
import { refreshAll } from '$app/navigation';
import { deserialize } from '$app/forms';
import { Loader2, Upload, FileText, Download, CheckCircle2, AlertCircle } from '@lucide/svelte';
import { Button } from '$lib/components/ui/button/index.js';
import * as Dialog from '$lib/components/ui/dialog/index.js';
import { downloadImportErrors } from '$lib/utils/csv.js';
import { Button } from '#lib/components/ui/button/index.js';
import * as Dialog from '#lib/components/ui/dialog/index.js';
import { downloadImportErrors } from '#lib/utils/csv.js';
/**
* Two-step CSV import flow: upload → preview → confirm.
@ -174,7 +174,7 @@
if (result.type === 'success' && result.data?.importCommit) {
commitResult = result.data.importCommit;
step = 'done';
await invalidateAll();
await refreshAll();
}
} catch (err) {
formError = err instanceof Error ? err.message : 'Import failed';

View file

@ -1,7 +1,7 @@
<script>
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { buttonVariants } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils.js';
import { buttonVariants } from '#lib/components/ui/button/index.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,7 +1,7 @@
<script>
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { buttonVariants } from '$lib/components/ui/button/index.js';
import { cn } from '$lib/utils.js';
import { buttonVariants } from '#lib/components/ui/button/index.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,7 +1,7 @@
<script>
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import AlertDialogOverlay from './alert-dialog-overlay.svelte';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,6 +1,6 @@
<script>
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,6 +1,6 @@
<script>
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,6 +1,6 @@
<script>
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,6 +1,6 @@
<script>
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
import { gradientFor, WORKSPACE_GRADIENT } from './avatar-gradients.js';
/**

View file

@ -1,6 +1,6 @@
<script>
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className, ...restProps } = $props();
</script>

View file

@ -1,6 +1,6 @@
<script>
import { Avatar as AvatarPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @typedef {'loading' | 'loaded' | 'error'} LoadingStatus

View file

@ -43,7 +43,7 @@
</script>
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,6 +1,6 @@
<script>
import { X } from '@lucide/svelte';
import { Button } from '$lib/components/ui/button/index.js';
import { Button } from '#lib/components/ui/button/index.js';
/** @typedef {{ label: string, onClick: () => void, variant?: 'default'|'outline'|'destructive' }} BulkAction */

View file

@ -1,5 +1,5 @@
<script module>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
import { tv } from 'tailwind-variants';
export const buttonVariants = tv({
@ -61,7 +61,7 @@
<script>
import { resolve } from '$app/paths';
import { asInternalPath } from '$lib/utils/paths.js';
import { asInternalPath } from '#lib/utils/paths.js';
/**
* @type {{
* class?: string,

View file

@ -1,7 +1,7 @@
<script>
import { Calendar } from 'bits-ui';
import { ChevronLeft, ChevronRight } from '@lucide/svelte';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
import { today, getLocalTimeZone } from '@internationalized/date';
/**

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/** @type {{ ref?: HTMLElement | null, class?: string, children?: import('svelte').Snippet, [key: string]: any }} */
let { ref = $bindable(null), class: className, children, ...restProps } = $props();
</script>

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className = undefined, children, ...restProps } = $props();
</script>

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className = undefined, children, ...restProps } = $props();
</script>

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className = undefined, children, ...restProps } = $props();
</script>

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,11 +1,11 @@
<script>
import { toast } from 'svelte-sonner';
import { MessageSquare, Send, Trash2, Loader2, ChevronDown, ChevronUp } from '@lucide/svelte';
import { Button } from '$lib/components/ui/button/index.js';
import { Textarea } from '$lib/components/ui/textarea/index.js';
import * as AlertDialog from '$lib/components/ui/alert-dialog/index.js';
import { formatRelativeDate, getInitials } from '$lib/utils/formatting.js';
import * as api from '$lib/api.js';
import { Button } from '#lib/components/ui/button/index.js';
import { Textarea } from '#lib/components/ui/textarea/index.js';
import * as AlertDialog from '#lib/components/ui/alert-dialog/index.js';
import { formatRelativeDate, getInitials } from '#lib/utils/formatting.js';
import * as api from '#lib/api.js';
import MentionBody from './MentionBody.svelte';
/**

View file

@ -1,7 +1,7 @@
<script>
import { SvelteMap } from 'svelte/reactivity';
import { resolve } from '$app/paths';
import { asInternalPath } from '$lib/utils/paths.js';
import { asInternalPath } from '#lib/utils/paths.js';
/**
* Render a comment body with `@username` tokens upgraded to styled chips.
*

View file

@ -1,5 +1,5 @@
<script>
import { Textarea } from '$lib/components/ui/textarea/index.js';
import { Textarea } from '#lib/components/ui/textarea/index.js';
/**
* Textarea with `@username` typeahead. Accepts the same props as the

View file

@ -1,10 +1,10 @@
<script>
import { resolve } from '$app/paths';
import { asInternalPath } from '$lib/utils/paths.js';
import { asInternalPath } from '#lib/utils/paths.js';
import { X, Trash2, Maximize2 } from '@lucide/svelte';
import * as Sheet from '$lib/components/ui/sheet/index.js';
import { Skeleton } from '$lib/components/ui/skeleton/index.js';
import { cn } from '$lib/utils.js';
import * as Sheet from '#lib/components/ui/sheet/index.js';
import { Skeleton } from '#lib/components/ui/skeleton/index.js';
import { cn } from '#lib/utils.js';
import CrmPropertyRow from './CrmPropertyRow.svelte';
/**

View file

@ -1,11 +1,11 @@
<script>
import { Check, Calendar as CalendarIcon } from '@lucide/svelte';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index.js';
import * as Popover from '$lib/components/ui/popover/index.js';
import { Calendar } from '$lib/components/ui/calendar/index.js';
import { EditableMultiSelect } from '$lib/components/ui/editable-field/index.js';
import { cn } from '$lib/utils.js';
import { formatCurrency } from '$lib/utils/formatting.js';
import * as DropdownMenu from '#lib/components/ui/dropdown-menu/index.js';
import * as Popover from '#lib/components/ui/popover/index.js';
import { Calendar } from '#lib/components/ui/calendar/index.js';
import { EditableMultiSelect } from '#lib/components/ui/editable-field/index.js';
import { cn } from '#lib/utils.js';
import { formatCurrency } from '#lib/utils/formatting.js';
import { parseDate } from '@internationalized/date';
/**

View file

@ -1,9 +1,9 @@
<script>
import { tick } from 'svelte';
import { Check, ChevronDown, Building2, User } from '@lucide/svelte';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index.js';
import { getOptionStyle, getOptionLabel, getOptionBgColor } from '$lib/utils/table-helpers.js';
import { formatCurrency } from '$lib/utils/formatting.js';
import * as DropdownMenu from '#lib/components/ui/dropdown-menu/index.js';
import { getOptionStyle, getOptionLabel, getOptionBgColor } from '#lib/utils/table-helpers.js';
import { formatCurrency } from '#lib/utils/formatting.js';
/**
* @typedef {Object} ColumnDef

View file

@ -3,7 +3,7 @@
import DialogPortal from './dialog-portal.svelte';
import XIcon from '@lucide/svelte/icons/x';
import * as Dialog from './index.js';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let {
ref = $bindable(null),
class: className = undefined,

View file

@ -1,6 +1,6 @@
<script>
import { Dialog as DialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className = undefined, ...restProps } = $props();
</script>

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className = undefined, children, ...restProps } = $props();
</script>

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className = undefined, children, ...restProps } = $props();
</script>

View file

@ -1,6 +1,6 @@
<script>
import { Dialog as DialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className, ...restProps } = $props();
</script>

View file

@ -1,6 +1,6 @@
<script>
import { Dialog as DialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className = undefined, ...restProps } = $props();
</script>

View file

@ -2,7 +2,7 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckIcon from '@lucide/svelte/icons/check';
import MinusIcon from '@lucide/svelte/icons/minus';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let {
ref = $bindable(null),
checked = $bindable(false),

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
/**

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
/**

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{
* ref?: HTMLElement | null,

View file

@ -1,6 +1,6 @@
<script>
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,9 +1,9 @@
<script>
import { ChevronDown, X, Search, AlertCircle, RotateCw } from '@lucide/svelte';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index.js';
import { Badge } from '$lib/components/ui/badge/index.js';
import { Skeleton } from '$lib/components/ui/skeleton/index.js';
import { cn } from '$lib/utils.js';
import * as DropdownMenu from '#lib/components/ui/dropdown-menu/index.js';
import { Badge } from '#lib/components/ui/badge/index.js';
import { Skeleton } from '#lib/components/ui/skeleton/index.js';
import { cn } from '#lib/utils.js';
/**
* @typedef {Object} SelectOption

View file

@ -1,9 +1,9 @@
<script>
import { CalendarDays, ChevronDown, X, Clock, ArrowRight } from '@lucide/svelte';
import { cn } from '$lib/utils.js';
import * as Popover from '$lib/components/ui/popover/index.js';
import Calendar from '$lib/components/ui/calendar/Calendar.svelte';
import { Button } from '$lib/components/ui/button/index.js';
import { cn } from '#lib/utils.js';
import * as Popover from '#lib/components/ui/popover/index.js';
import Calendar from '#lib/components/ui/calendar/Calendar.svelte';
import { Button } from '#lib/components/ui/button/index.js';
import { today, getLocalTimeZone, parseDate } from '@internationalized/date';
/**

View file

@ -1,7 +1,7 @@
<script>
import { Filter, X, ChevronDown, Sparkles } from '@lucide/svelte';
import { cn } from '$lib/utils.js';
import { Button } from '$lib/components/ui/button/index.js';
import { cn } from '#lib/utils.js';
import { Button } from '#lib/components/ui/button/index.js';
/**
* @type {{

View file

@ -1,7 +1,7 @@
<script>
import { ChevronDown, Check, X } from '@lucide/svelte';
import { cn } from '$lib/utils.js';
import * as Popover from '$lib/components/ui/popover/index.js';
import { cn } from '#lib/utils.js';
import * as Popover from '#lib/components/ui/popover/index.js';
/**
* @typedef {{

View file

@ -1,7 +1,7 @@
<script>
import { ChevronDown, Check, X, Tag, Hash } from '@lucide/svelte';
import { cn } from '$lib/utils.js';
import * as Popover from '$lib/components/ui/popover/index.js';
import { cn } from '#lib/utils.js';
import * as Popover from '#lib/components/ui/popover/index.js';
/**
* @typedef {{

View file

@ -1,6 +1,6 @@
<script>
import { enhance } from '$app/forms';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @typedef {Object} Props
@ -8,7 +8,7 @@
* @property {string} [action]
* @property {'application/x-www-form-urlencoded' | 'multipart/form-data' | 'text/plain'} [enctype]
* @property {(this: HTMLFormElement, event: SubmitEvent) => void} [onsubmit]
* @property {import('@sveltejs/kit').SubmitFunction} [useEnhance]
* @property {import('$app/forms').SubmitFunction} [useEnhance]
* @property {string} [class]
* @property {string} [errorMessage]
* @property {import('svelte').Snippet} children

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,6 +1,6 @@
<script>
import { Label as LabelPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className = undefined, ...restProps } = $props();
</script>

View file

@ -1,7 +1,7 @@
<script>
import { ChevronLeft, ChevronRight, ChevronsUpDown } from '@lucide/svelte';
import * as Popover from '$lib/components/ui/popover/index.js';
import { cn } from '$lib/utils.js';
import * as Popover from '#lib/components/ui/popover/index.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
import { Popover as PopoverPrimitive } from 'bits-ui';
/**

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
import { Popover as PopoverPrimitive } from 'bits-ui';
let { ref = $bindable(null), class: className, ...restProps } = $props();

View file

@ -1,6 +1,6 @@
<script>
import { Progress as ProgressPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className, max = 100, value, ...restProps } = $props();
</script>

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -3,7 +3,7 @@
import SelectPortal from './select-portal.svelte';
import SelectScrollUpButton from './select-scroll-up-button.svelte';
import SelectScrollDownButton from './select-scroll-down-button.svelte';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let {
ref = $bindable(null),
class: className = '',

View file

@ -1,6 +1,6 @@
<script>
import { Select as SelectPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className, children, ...restProps } = $props();
</script>

View file

@ -1,7 +1,7 @@
<script>
import CheckIcon from '@lucide/svelte/icons/check';
import { Select as SelectPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let {
ref = $bindable(null),

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className, children, ...restProps } = $props();
</script>

View file

@ -1,7 +1,7 @@
<script>
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
import { Select as SelectPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className = '', ...restProps } = $props();
</script>

View file

@ -1,7 +1,7 @@
<script>
import ChevronUpIcon from '@lucide/svelte/icons/chevron-up';
import { Select as SelectPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className = '', ...restProps } = $props();
</script>

View file

@ -1,6 +1,6 @@
<script>
import { Separator } from '$lib/components/ui/separator/index.js';
import { cn } from '$lib/utils.js';
import { Separator } from '#lib/components/ui/separator/index.js';
import { cn } from '#lib/utils.js';
let { ref = $bindable(null), class: className, ...restProps } = $props();
</script>

View file

@ -1,7 +1,7 @@
<script>
import { Select as SelectPrimitive } from 'bits-ui';
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let {
ref = $bindable(null),

View file

@ -1,6 +1,6 @@
<script>
import { Separator as SeparatorPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
let {
ref = $bindable(null),

View file

@ -21,7 +21,7 @@
<script>
import { Dialog as SheetPrimitive } from 'bits-ui';
import SheetOverlay from './sheet-overlay.svelte';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,6 +1,6 @@
<script>
import { Dialog as SheetPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,5 +1,5 @@
<script>
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,6 +1,6 @@
<script>
import { Dialog as SheetPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,6 +1,6 @@
<script>
import { Dialog as SheetPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
/**
* @type {{

View file

@ -1,6 +1,6 @@
<script>
import { X, ChevronLeft } from '@lucide/svelte';
import { cn } from '$lib/utils.js';
import { cn } from '#lib/utils.js';
import { sidePanelHidden } from './index.js';
/**

Some files were not shown because too many files have changed in this diff Show more