This commit is contained in:
Raj Nandan Sharma
2026-01-22 18:29:42 +05:30
parent 0149b3e61a
commit 6b88cf11a1
225 changed files with 4158 additions and 4484 deletions
Vendored
BIN
View File
Binary file not shown.
+2 -1
View File
@@ -28,4 +28,5 @@ uploads/*
static/uploads/* static/uploads/*
!static/uploads/upload.dir !static/uploads/upload.dir
temp.txt temp.txt
temp.js temp.js
.DS_Store
+14 -14
View File
@@ -1,16 +1,16 @@
{ {
"$schema": "https://shadcn-svelte.com/schema.json", "$schema": "https://shadcn-svelte.com/schema.json",
"tailwind": { "tailwind": {
"css": "src/routes/layout.css", "css": "src/routes/layout.css",
"baseColor": "zinc" "baseColor": "zinc"
}, },
"aliases": { "aliases": {
"components": "$lib/components", "components": "$lib/components",
"utils": "$lib/utils", "utils": "$lib/utils",
"ui": "$lib/components/ui", "ui": "$lib/components/ui",
"hooks": "$lib/hooks", "hooks": "$lib/hooks",
"lib": "$lib" "lib": "$lib"
}, },
"typescript": true, "typescript": true,
"registry": "https://shadcn-svelte.com/registry" "registry": "https://shadcn-svelte.com/registry"
} }
+126 -128
View File
@@ -1,135 +1,133 @@
// migrations/YYYYMMDDHHMMSS_create_monitoring_tables.js // migrations/YYYYMMDDHHMMSS_create_monitoring_tables.js
export function up(knex) { export function up(knex) {
return ( return (
knex.schema knex.schema
// Create monitoring_data table // Create monitoring_data table
.createTable("monitoring_data", (table) => { .createTable("monitoring_data", (table) => {
table.string("monitor_tag", 255).notNullable(); table.string("monitor_tag", 255).notNullable();
table.integer("timestamp").notNullable(); table.integer("timestamp").notNullable();
table.text("status"); table.text("status");
table.float("latency", 8, 2); table.float("latency", 8, 2);
table.text("type"); table.text("type");
table.primary(["monitor_tag", "timestamp"]); table.primary(["monitor_tag", "timestamp"]);
}) })
// Create monitor_alerts table // Create monitor_alerts table
.createTable("monitor_alerts", (table) => { .createTable("monitor_alerts", (table) => {
table.increments("id").primary(); table.increments("id").primary();
table.string("monitor_tag", 255).notNullable(); table.string("monitor_tag", 255).notNullable();
table.string("monitor_status", 255).notNullable(); table.string("monitor_status", 255).notNullable();
table.string("alert_status", 255).notNullable(); table.string("alert_status", 255).notNullable();
table.integer("health_checks").notNullable(); table.integer("health_checks").notNullable();
table.integer("incident_number").defaultTo(0); table.integer("incident_number").defaultTo(0);
table.timestamp("created_at").defaultTo(knex.fn.now()); table.timestamp("created_at").defaultTo(knex.fn.now());
table.timestamp("updated_at").defaultTo(knex.fn.now()); table.timestamp("updated_at").defaultTo(knex.fn.now());
}) })
// Add index to monitor_alerts table // Add index to monitor_alerts table
.raw( .raw("CREATE INDEX idx_monitor_tag_created_at ON monitor_alerts (monitor_tag, created_at)")
"CREATE INDEX idx_monitor_tag_created_at ON monitor_alerts (monitor_tag, created_at)" .createTable("site_data", (table) => {
) table.increments("id").primary();
.createTable("site_data", (table) => { table.string("key", 255).notNullable().unique();
table.increments("id").primary(); table.text("value").notNullable();
table.string("key", 255).notNullable().unique(); table.string("data_type", 255).notNullable();
table.text("value").notNullable(); table.timestamp("created_at").defaultTo(knex.fn.now());
table.string("data_type", 255).notNullable(); table.timestamp("updated_at").defaultTo(knex.fn.now());
table.timestamp("created_at").defaultTo(knex.fn.now()); })
table.timestamp("updated_at").defaultTo(knex.fn.now()); .createTable("monitors", (table) => {
}) table.increments("id").primary();
.createTable("monitors", (table) => { table.string("tag", 255).notNullable().unique();
table.increments("id").primary(); table.string("name", 255).notNullable().unique();
table.string("tag", 255).notNullable().unique(); table.text("description");
table.string("name", 255).notNullable().unique(); table.text("image");
table.text("description"); table.string("cron", 255);
table.text("image"); table.string("default_status", 255);
table.string("cron", 255); table.string("status", 255);
table.string("default_status", 255); table.string("category_name", 255);
table.string("status", 255); table.string("monitor_type", 255);
table.string("category_name", 255); table.string("down_trigger", 255);
table.string("monitor_type", 255); table.string("degraded_trigger", 255);
table.string("down_trigger", 255); table.text("type_data");
table.string("degraded_trigger", 255); table.integer("day_degraded_minimum_count");
table.text("type_data"); table.integer("day_down_minimum_count");
table.integer("day_degraded_minimum_count"); table.string("include_degraded_in_downtime", 255).defaultTo("NO");
table.integer("day_down_minimum_count"); table.timestamp("created_at").defaultTo(knex.fn.now());
table.string("include_degraded_in_downtime", 255).defaultTo("NO"); table.timestamp("updated_at").defaultTo(knex.fn.now());
table.timestamp("created_at").defaultTo(knex.fn.now()); })
table.timestamp("updated_at").defaultTo(knex.fn.now()); .createTable("triggers", (table) => {
}) table.increments("id").primary();
.createTable("triggers", (table) => { table.string("name", 255).notNullable().unique();
table.increments("id").primary(); table.string("trigger_type", 255);
table.string("name", 255).notNullable().unique(); table.text("trigger_desc");
table.string("trigger_type", 255); table.string("trigger_status", 255);
table.text("trigger_desc"); table.text("trigger_meta");
table.string("trigger_status", 255); table.timestamp("created_at").defaultTo(knex.fn.now());
table.text("trigger_meta"); table.timestamp("updated_at").defaultTo(knex.fn.now());
table.timestamp("created_at").defaultTo(knex.fn.now()); })
table.timestamp("updated_at").defaultTo(knex.fn.now()); .createTable("users", (table) => {
}) table.increments("id").primary();
.createTable("users", (table) => { table.string("email", 255).notNullable().unique();
table.increments("id").primary(); table.string("name", 255).notNullable();
table.string("email", 255).notNullable().unique(); table.string("password_hash", 255).notNullable();
table.string("name", 255).notNullable(); table.integer("is_active").defaultTo(1);
table.string("password_hash", 255).notNullable(); table.integer("is_verified").defaultTo(0);
table.integer("is_active").defaultTo(1); table.string("role", 255).defaultTo("user");
table.integer("is_verified").defaultTo(0); table.timestamp("created_at").defaultTo(knex.fn.now());
table.string("role", 255).defaultTo("user"); table.timestamp("updated_at").defaultTo(knex.fn.now());
table.timestamp("created_at").defaultTo(knex.fn.now()); })
table.timestamp("updated_at").defaultTo(knex.fn.now()); .createTable("api_keys", (table) => {
}) table.increments("id").primary();
.createTable("api_keys", (table) => { table.string("name", 255).notNullable().unique();
table.increments("id").primary(); table.string("hashed_key", 255).notNullable().unique();
table.string("name", 255).notNullable().unique(); table.string("masked_key", 255).notNullable();
table.string("hashed_key", 255).notNullable().unique(); table.string("status", 255).defaultTo("ACTIVE");
table.string("masked_key", 255).notNullable(); table.timestamp("created_at").defaultTo(knex.fn.now());
table.string("status", 255).defaultTo("ACTIVE"); table.timestamp("updated_at").defaultTo(knex.fn.now());
table.timestamp("created_at").defaultTo(knex.fn.now()); })
table.timestamp("updated_at").defaultTo(knex.fn.now()); .createTable("incidents", (table) => {
}) table.increments("id").primary();
.createTable("incidents", (table) => { table.string("title", 255).notNullable();
table.increments("id").primary(); table.integer("start_date_time").notNullable();
table.string("title", 255).notNullable(); table.integer("end_date_time");
table.integer("start_date_time").notNullable(); table.timestamp("created_at").defaultTo(knex.fn.now());
table.integer("end_date_time"); table.timestamp("updated_at").defaultTo(knex.fn.now());
table.timestamp("created_at").defaultTo(knex.fn.now()); table.string("status", 255).defaultTo("ACTIVE");
table.timestamp("updated_at").defaultTo(knex.fn.now()); table.string("state", 255).defaultTo("INVESTIGATING");
table.string("status", 255).defaultTo("ACTIVE"); })
table.string("state", 255).defaultTo("INVESTIGATING"); .createTable("incident_monitors", (table) => {
}) table.increments("id").primary();
.createTable("incident_monitors", (table) => { table.string("monitor_tag", 255).notNullable();
table.increments("id").primary(); table.string("monitor_impact", 255);
table.string("monitor_tag", 255).notNullable(); table.timestamp("created_at").defaultTo(knex.fn.now());
table.string("monitor_impact", 255); table.timestamp("updated_at").defaultTo(knex.fn.now());
table.timestamp("created_at").defaultTo(knex.fn.now()); table.integer("incident_id").notNullable();
table.timestamp("updated_at").defaultTo(knex.fn.now()); table.unique(["monitor_tag", "incident_id"]);
table.integer("incident_id").notNullable(); })
table.unique(["monitor_tag", "incident_id"]); .createTable("incident_comments", (table) => {
}) table.increments("id").primary();
.createTable("incident_comments", (table) => { table.text("comment").notNullable();
table.increments("id").primary(); table.integer("incident_id").notNullable();
table.text("comment").notNullable(); table.integer("commented_at").notNullable();
table.integer("incident_id").notNullable(); table.timestamp("created_at").defaultTo(knex.fn.now());
table.integer("commented_at").notNullable(); table.timestamp("updated_at").defaultTo(knex.fn.now());
table.timestamp("created_at").defaultTo(knex.fn.now()); table.string("status", 255).defaultTo("ACTIVE");
table.timestamp("updated_at").defaultTo(knex.fn.now()); table.string("state", 255).defaultTo("INVESTIGATING");
table.string("status", 255).defaultTo("ACTIVE"); })
table.string("state", 255).defaultTo("INVESTIGATING"); );
})
);
} }
export function down(knex) { export function down(knex) {
return ( return (
knex.schema knex.schema
// Drop tables in reverse order // Drop tables in reverse order
.dropTableIfExists("monitor_alerts") .dropTableIfExists("monitor_alerts")
.dropTableIfExists("monitoring_data") .dropTableIfExists("monitoring_data")
.dropTableIfExists("site_data") .dropTableIfExists("site_data")
.dropTableIfExists("monitors") .dropTableIfExists("monitors")
.dropTableIfExists("triggers") .dropTableIfExists("triggers")
.dropTableIfExists("users") .dropTableIfExists("users")
.dropTableIfExists("api_keys") .dropTableIfExists("api_keys")
.dropTableIfExists("incidents") .dropTableIfExists("incidents")
.dropTableIfExists("incident_monitors") .dropTableIfExists("incident_monitors")
.dropTableIfExists("incident_comments") .dropTableIfExists("incident_comments")
); );
} }
@@ -1,11 +1,11 @@
export function up(knex) { export function up(knex) {
return knex.schema.alterTable("incidents", function (table) { return knex.schema.alterTable("incidents", function (table) {
table.text("incident_type").defaultTo("INCIDENT"); table.text("incident_type").defaultTo("INCIDENT");
}); });
} }
export function down(knex) { export function down(knex) {
return knex.schema.alterTable("incidents", function (table) { return knex.schema.alterTable("incidents", function (table) {
table.dropColumn("incident_type"); table.dropColumn("incident_type");
}); });
} }
+2 -359
View File
@@ -128,8 +128,8 @@
} }
}, },
"../aven": { "../aven": {
"name": "@rajnandan1/aven", "name": "@rajnandan1/atticus",
"version": "0.1.1", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@openai/agents": "^0.3.7", "@openai/agents": "^0.3.7",
@@ -3008,17 +3008,6 @@
"hono": "^4" "hono": "^4"
} }
}, },
"node_modules/@modelcontextprotocol/sdk/node_modules/hono": {
"version": "4.11.5",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.11.5.tgz",
"integrity": "sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g==",
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=16.9.0"
}
},
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
@@ -3168,29 +3157,6 @@
} }
} }
}, },
"node_modules/@openai/agents-core/node_modules/ws": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/@openai/agents-openai": { "node_modules/@openai/agents-openai": {
"version": "0.3.9", "version": "0.3.9",
"resolved": "https://registry.npmjs.org/@openai/agents-openai/-/agents-openai-0.3.9.tgz", "resolved": "https://registry.npmjs.org/@openai/agents-openai/-/agents-openai-0.3.9.tgz",
@@ -3226,29 +3192,6 @@
} }
} }
}, },
"node_modules/@openai/agents-openai/node_modules/ws": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/@openai/agents-realtime": { "node_modules/@openai/agents-realtime": {
"version": "0.3.9", "version": "0.3.9",
"resolved": "https://registry.npmjs.org/@openai/agents-realtime/-/agents-realtime-0.3.9.tgz", "resolved": "https://registry.npmjs.org/@openai/agents-realtime/-/agents-realtime-0.3.9.tgz",
@@ -3306,29 +3249,6 @@
} }
} }
}, },
"node_modules/@openai/agents/node_modules/ws": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/@polka/url": { "node_modules/@polka/url": {
"version": "1.0.0-next.29", "version": "1.0.0-next.29",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
@@ -8291,268 +8211,6 @@
"svelte": "^5.7.0" "svelte": "^5.7.0"
} }
}, },
"node_modules/lightningcss": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz",
"integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==",
"license": "MPL-2.0",
"optional": true,
"peer": true,
"dependencies": {
"detect-libc": "^2.0.3"
},
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"lightningcss-android-arm64": "1.31.1",
"lightningcss-darwin-arm64": "1.31.1",
"lightningcss-darwin-x64": "1.31.1",
"lightningcss-freebsd-x64": "1.31.1",
"lightningcss-linux-arm-gnueabihf": "1.31.1",
"lightningcss-linux-arm64-gnu": "1.31.1",
"lightningcss-linux-arm64-musl": "1.31.1",
"lightningcss-linux-x64-gnu": "1.31.1",
"lightningcss-linux-x64-musl": "1.31.1",
"lightningcss-win32-arm64-msvc": "1.31.1",
"lightningcss-win32-x64-msvc": "1.31.1"
}
},
"node_modules/lightningcss-android-arm64": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz",
"integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"android"
],
"peer": true,
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-darwin-arm64": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz",
"integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-darwin-x64": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz",
"integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-freebsd-x64": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz",
"integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"freebsd"
],
"peer": true,
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm-gnueabihf": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz",
"integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==",
"cpu": [
"arm"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-gnu": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz",
"integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-musl": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz",
"integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-gnu": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz",
"integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-musl": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz",
"integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-arm64-msvc": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz",
"integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==",
"cpu": [
"arm64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-x64-msvc": {
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz",
"integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==",
"cpu": [
"x64"
],
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lilconfig": { "node_modules/lilconfig": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
@@ -12839,21 +12497,6 @@
} }
} }
}, },
"node_modules/svelte-check/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/svelte-codemirror-editor": { "node_modules/svelte-codemirror-editor": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/svelte-codemirror-editor/-/svelte-codemirror-editor-2.1.0.tgz", "resolved": "https://registry.npmjs.org/svelte-codemirror-editor/-/svelte-codemirror-editor-2.1.0.tgz",
+2
View File
@@ -21,6 +21,8 @@ export async function seed(knex: Knex): Promise<void> {
day_degraded_minimum_count: monitor.day_degraded_minimum_count, day_degraded_minimum_count: monitor.day_degraded_minimum_count,
day_down_minimum_count: monitor.day_down_minimum_count, day_down_minimum_count: monitor.day_down_minimum_count,
include_degraded_in_downtime: monitor.include_degraded_in_downtime, include_degraded_in_downtime: monitor.include_degraded_in_downtime,
is_hidden: monitor.is_hidden || "NO",
monitor_settings_json: monitor.monitor_settings_json || null,
created_at: knex.fn.now(), created_at: knex.fn.now(),
updated_at: knex.fn.now(), updated_at: knex.fn.now(),
}); });
+2 -2
View File
@@ -64,7 +64,7 @@
{/if} {/if}
<header class="sticky top-0 z-50 mx-auto md:mt-2"> <header class="sticky top-0 z-50 mx-auto md:mt-2">
<div class="container flex h-14 max-w-[820px] items-center border bg-card px-3 md:rounded-md"> <div class="bg-card container flex h-14 max-w-[820px] items-center border px-3 md:rounded-md">
<a rel="external" href={data.site.home ? data.site.home : base} class="mr-6 flex items-center space-x-2"> <a rel="external" href={data.site.home ? data.site.home : base} class="mr-6 flex items-center space-x-2">
{#if data.site.logo} {#if data.site.logo}
<GMI src={data.site.logo} classList="w-8" alt={data.site.title} srcset="" /> <GMI src={data.site.logo} classList="w-8" alt={data.site.title} srcset="" />
@@ -82,7 +82,7 @@
<a <a
rel="external" rel="external"
href={navItem.url} href={navItem.url}
class="flex rounded-md px-3 py-2 text-card-foreground transition-all ease-linear hover:bg-background" class="text-card-foreground hover:bg-background flex rounded-md px-3 py-2 transition-all ease-linear"
on:click={() => on:click={() =>
analyticsEvent("navigation", { analyticsEvent("navigation", {
name: navItem.name name: navItem.name
+5 -5
View File
@@ -140,7 +140,7 @@
<h2 class="mb-1 text-sm font-semibold"> <h2 class="mb-1 text-sm font-semibold">
{l(lang, "Share")} {l(lang, "Share")}
</h2> </h2>
<p class="mb-2 text-xs text-muted-foreground"> <p class="text-muted-foreground mb-2 text-xs">
{l(lang, "Share this monitor using a link with others")} {l(lang, "Share this monitor using a link with others")}
</p> </p>
<Button class="h-8 px-2 pr-4 text-xs font-semibold" variant="secondary" on:click={copyLinkToClipboard}> <Button class="h-8 px-2 pr-4 text-xs font-semibold" variant="secondary" on:click={copyLinkToClipboard}>
@@ -160,7 +160,7 @@
href={pathMonitorLink} href={pathMonitorLink}
target="_blank" target="_blank"
variant="link" variant="link"
class="h-8 px-3 text-xs font-semibold text-muted-foreground" class="text-muted-foreground h-8 px-3 text-xs font-semibold"
> >
<ExternalLink class="inline" size={12} /> <ExternalLink class="inline" size={12} />
</Button> </Button>
@@ -170,7 +170,7 @@
<h2 class="mb-1 text-sm font-semibold"> <h2 class="mb-1 text-sm font-semibold">
{l(lang, "Embed")} {l(lang, "Embed")}
</h2> </h2>
<p class="mb-1 text-xs text-muted-foreground"> <p class="text-muted-foreground mb-1 text-xs">
{l(lang, "Embed this monitor using &#x3C;script&#x3E; or &#x3C;iframe&#x3E; in your app.")} {l(lang, "Embed this monitor using &#x3C;script&#x3E; or &#x3C;iframe&#x3E; in your app.")}
</p> </p>
<div class="mb-4 grid grid-cols-2 gap-2"> <div class="mb-4 grid grid-cols-2 gap-2">
@@ -226,7 +226,7 @@
<h2 class="mb-1 text-sm font-semibold"> <h2 class="mb-1 text-sm font-semibold">
{l(lang, "Badge")} {l(lang, "Badge")}
</h2> </h2>
<p class="mb-2 text-xs text-muted-foreground"> <p class="text-muted-foreground mb-2 text-xs">
{l(lang, "Get SVG badge for this monitor")} {l(lang, "Get SVG badge for this monitor")}
</p> </p>
<Button class="h-8 px-2 pr-4 text-xs" variant="secondary" on:click={copyStatusBadge}> <Button class="h-8 px-2 pr-4 text-xs" variant="secondary" on:click={copyStatusBadge}>
@@ -263,7 +263,7 @@
<h2 class="mb-1 text-sm font-semibold"> <h2 class="mb-1 text-sm font-semibold">
{l(lang, "LIVE Status")} {l(lang, "LIVE Status")}
</h2> </h2>
<p class="mb-2 text-xs text-muted-foreground"> <p class="text-muted-foreground mb-2 text-xs">
{l(lang, "Get a LIVE Status for this monitor")} {l(lang, "Get a LIVE Status for this monitor")}
</p> </p>
<Button class="h-8 px-2 pr-4 text-xs" variant="secondary" on:click={copyDotStandard}> <Button class="h-8 px-2 pr-4 text-xs" variant="secondary" on:click={copyDotStandard}>
@@ -1,22 +1,22 @@
<script lang="ts"> <script lang="ts">
import { Accordion as AccordionPrimitive } from "bits-ui"; import { Accordion as AccordionPrimitive } from "bits-ui";
import { cn, type WithoutChild } from "$lib/utils.js"; import { cn, type WithoutChild } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithoutChild<AccordionPrimitive.ContentProps> = $props(); }: WithoutChild<AccordionPrimitive.ContentProps> = $props();
</script> </script>
<AccordionPrimitive.Content <AccordionPrimitive.Content
bind:ref bind:ref
data-slot="accordion-content" data-slot="accordion-content"
class="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm" class="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
{...restProps} {...restProps}
> >
<div class={cn("pt-0 pb-4", className)}> <div class={cn("pt-0 pb-4", className)}>
{@render children?.()} {@render children?.()}
</div> </div>
</AccordionPrimitive.Content> </AccordionPrimitive.Content>
@@ -1,17 +1,13 @@
<script lang="ts"> <script lang="ts">
import { Accordion as AccordionPrimitive } from "bits-ui"; import { Accordion as AccordionPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
let { let { ref = $bindable(null), class: className, ...restProps }: AccordionPrimitive.ItemProps = $props();
ref = $bindable(null),
class: className,
...restProps
}: AccordionPrimitive.ItemProps = $props();
</script> </script>
<AccordionPrimitive.Item <AccordionPrimitive.Item
bind:ref bind:ref
data-slot="accordion-item" data-slot="accordion-item"
class={cn("border-b last:border-b-0", className)} class={cn("border-b last:border-b-0", className)}
{...restProps} {...restProps}
/> />
@@ -1,32 +1,32 @@
<script lang="ts"> <script lang="ts">
import { Accordion as AccordionPrimitive } from "bits-ui"; import { Accordion as AccordionPrimitive } from "bits-ui";
import ChevronDownIcon from "@lucide/svelte/icons/chevron-down"; import ChevronDownIcon from "@lucide/svelte/icons/chevron-down";
import { cn, type WithoutChild } from "$lib/utils.js"; import { cn, type WithoutChild } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
level = 3, level = 3,
children, children,
...restProps ...restProps
}: WithoutChild<AccordionPrimitive.TriggerProps> & { }: WithoutChild<AccordionPrimitive.TriggerProps> & {
level?: AccordionPrimitive.HeaderProps["level"]; level?: AccordionPrimitive.HeaderProps["level"];
} = $props(); } = $props();
</script> </script>
<AccordionPrimitive.Header {level} class="flex"> <AccordionPrimitive.Header {level} class="flex">
<AccordionPrimitive.Trigger <AccordionPrimitive.Trigger
data-slot="accordion-trigger" data-slot="accordion-trigger"
bind:ref bind:ref
class={cn( class={cn(
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-start text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180", "focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-start text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
className className
)} )}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
<ChevronDownIcon <ChevronDownIcon
class="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" class="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200"
/> />
</AccordionPrimitive.Trigger> </AccordionPrimitive.Trigger>
</AccordionPrimitive.Header> </AccordionPrimitive.Header>
@@ -1,16 +1,7 @@
<script lang="ts"> <script lang="ts">
import { Accordion as AccordionPrimitive } from "bits-ui"; import { Accordion as AccordionPrimitive } from "bits-ui";
let { let { ref = $bindable(null), value = $bindable(), ...restProps }: AccordionPrimitive.RootProps = $props();
ref = $bindable(null),
value = $bindable(),
...restProps
}: AccordionPrimitive.RootProps = $props();
</script> </script>
<AccordionPrimitive.Root <AccordionPrimitive.Root bind:ref bind:value={value as never} data-slot="accordion" {...restProps} />
bind:ref
bind:value={value as never}
data-slot="accordion"
{...restProps}
/>
+9 -9
View File
@@ -4,13 +4,13 @@ import Item from "./accordion-item.svelte";
import Trigger from "./accordion-trigger.svelte"; import Trigger from "./accordion-trigger.svelte";
export { export {
Root, Root,
Content, Content,
Item, Item,
Trigger, Trigger,
// //
Root as Accordion, Root as Accordion,
Content as AccordionContent, Content as AccordionContent,
Item as AccordionItem, Item as AccordionItem,
Trigger as AccordionTrigger, Trigger as AccordionTrigger,
}; };
@@ -1,23 +1,23 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="alert-description" data-slot="alert-description"
class={cn( class={cn(
"text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed", "text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
className className
)} )}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
+13 -13
View File
@@ -1,20 +1,20 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="alert-title" data-slot="alert-title"
class={cn("col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight", className)} class={cn("col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight", className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
+27 -34
View File
@@ -1,44 +1,37 @@
<script lang="ts" module> <script lang="ts" module>
import { type VariantProps, tv } from "tailwind-variants"; import { type VariantProps, tv } from "tailwind-variants";
export const alertVariants = tv({ export const alertVariants = tv({
base: "relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", base: "relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
variants: { variants: {
variant: { variant: {
default: "bg-card text-card-foreground", default: "bg-card text-card-foreground",
destructive: destructive: "text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-current"
"text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-current", }
}, },
}, defaultVariants: {
defaultVariants: { variant: "default"
variant: "default", }
}, });
});
export type AlertVariant = VariantProps<typeof alertVariants>["variant"]; export type AlertVariant = VariantProps<typeof alertVariants>["variant"];
</script> </script>
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
variant = "default", variant = "default",
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & { }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
variant?: AlertVariant; variant?: AlertVariant;
} = $props(); } = $props();
</script> </script>
<div <div bind:this={ref} data-slot="alert" class={cn(alertVariants({ variant }), className)} {...restProps} role="alert">
bind:this={ref} {@render children?.()}
data-slot="alert"
class={cn(alertVariants({ variant }), className)}
{...restProps}
role="alert"
>
{@render children?.()}
</div> </div>
+7 -7
View File
@@ -4,11 +4,11 @@ import Title from "./alert-title.svelte";
export { alertVariants, type AlertVariant } from "./alert.svelte"; export { alertVariants, type AlertVariant } from "./alert.svelte";
export { export {
Root, Root,
Description, Description,
Title, Title,
// //
Root as Alert, Root as Alert,
Description as AlertDescription, Description as AlertDescription,
Title as AlertTitle, Title as AlertTitle,
}; };
@@ -1,17 +1,13 @@
<script lang="ts"> <script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui"; import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
let { let { ref = $bindable(null), class: className, ...restProps }: AvatarPrimitive.FallbackProps = $props();
ref = $bindable(null),
class: className,
...restProps
}: AvatarPrimitive.FallbackProps = $props();
</script> </script>
<AvatarPrimitive.Fallback <AvatarPrimitive.Fallback
bind:ref bind:ref
data-slot="avatar-fallback" data-slot="avatar-fallback"
class={cn("bg-muted flex size-full items-center justify-center rounded-full", className)} class={cn("bg-muted flex size-full items-center justify-center rounded-full", className)}
{...restProps} {...restProps}
/> />
@@ -1,17 +1,13 @@
<script lang="ts"> <script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui"; import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
let { let { ref = $bindable(null), class: className, ...restProps }: AvatarPrimitive.ImageProps = $props();
ref = $bindable(null),
class: className,
...restProps
}: AvatarPrimitive.ImageProps = $props();
</script> </script>
<AvatarPrimitive.Image <AvatarPrimitive.Image
bind:ref bind:ref
data-slot="avatar-image" data-slot="avatar-image"
class={cn("aspect-square size-full", className)} class={cn("aspect-square size-full", className)}
{...restProps} {...restProps}
/> />
+13 -13
View File
@@ -1,19 +1,19 @@
<script lang="ts"> <script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui"; import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
loadingStatus = $bindable("loading"), loadingStatus = $bindable("loading"),
class: className, class: className,
...restProps ...restProps
}: AvatarPrimitive.RootProps = $props(); }: AvatarPrimitive.RootProps = $props();
</script> </script>
<AvatarPrimitive.Root <AvatarPrimitive.Root
bind:ref bind:ref
bind:loadingStatus bind:loadingStatus
data-slot="avatar" data-slot="avatar"
class={cn("relative flex size-8 shrink-0 overflow-hidden rounded-full", className)} class={cn("relative flex size-8 shrink-0 overflow-hidden rounded-full", className)}
{...restProps} {...restProps}
/> />
+7 -7
View File
@@ -3,11 +3,11 @@ import Image from "./avatar-image.svelte";
import Fallback from "./avatar-fallback.svelte"; import Fallback from "./avatar-fallback.svelte";
export { export {
Root, Root,
Image, Image,
Fallback, Fallback,
// //
Root as Avatar, Root as Avatar,
Image as AvatarImage, Image as AvatarImage,
Fallback as AvatarFallback, Fallback as AvatarFallback,
}; };
+36 -38
View File
@@ -1,50 +1,48 @@
<script lang="ts" module> <script lang="ts" module>
import { type VariantProps, tv } from "tailwind-variants"; import { type VariantProps, tv } from "tailwind-variants";
export const badgeVariants = tv({ export const badgeVariants = tv({
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] [&>svg]:pointer-events-none [&>svg]:size-3", base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] [&>svg]:pointer-events-none [&>svg]:size-3",
variants: { variants: {
variant: { variant: {
default: default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90 border-transparent",
"bg-primary text-primary-foreground [a&]:hover:bg-primary/90 border-transparent", secondary: "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90 border-transparent",
secondary: destructive:
"bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90 border-transparent", "bg-destructive [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/70 border-transparent text-white",
destructive: outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
"bg-destructive [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/70 border-transparent text-white", }
outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", },
}, defaultVariants: {
}, variant: "default"
defaultVariants: { }
variant: "default", });
},
});
export type BadgeVariant = VariantProps<typeof badgeVariants>["variant"]; export type BadgeVariant = VariantProps<typeof badgeVariants>["variant"];
</script> </script>
<script lang="ts"> <script lang="ts">
import type { HTMLAnchorAttributes } from "svelte/elements"; import type { HTMLAnchorAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
href, href,
class: className, class: className,
variant = "default", variant = "default",
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAnchorAttributes> & { }: WithElementRef<HTMLAnchorAttributes> & {
variant?: BadgeVariant; variant?: BadgeVariant;
} = $props(); } = $props();
</script> </script>
<svelte:element <svelte:element
this={href ? "a" : "span"} this={href ? "a" : "span"}
bind:this={ref} bind:this={ref}
data-slot="badge" data-slot="badge"
{href} {href}
class={cn(badgeVariants({ variant }), className)} class={cn(badgeVariants({ variant }), className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</svelte:element> </svelte:element>
@@ -1,23 +1,23 @@
<script lang="ts"> <script lang="ts">
import EllipsisIcon from "@lucide/svelte/icons/ellipsis"; import EllipsisIcon from "@lucide/svelte/icons/ellipsis";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef, type WithoutChildren } from "$lib/utils.js"; import { cn, type WithElementRef, type WithoutChildren } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
...restProps ...restProps
}: WithoutChildren<WithElementRef<HTMLAttributes<HTMLSpanElement>>> = $props(); }: WithoutChildren<WithElementRef<HTMLAttributes<HTMLSpanElement>>> = $props();
</script> </script>
<span <span
bind:this={ref} bind:this={ref}
data-slot="breadcrumb-ellipsis" data-slot="breadcrumb-ellipsis"
role="presentation" role="presentation"
aria-hidden="true" aria-hidden="true"
class={cn("flex size-9 items-center justify-center", className)} class={cn("flex size-9 items-center justify-center", className)}
{...restProps} {...restProps}
> >
<EllipsisIcon class="size-4" /> <EllipsisIcon class="size-4" />
<span class="sr-only">More</span> <span class="sr-only">More</span>
</span> </span>
@@ -1,20 +1,15 @@
<script lang="ts"> <script lang="ts">
import type { HTMLLiAttributes } from "svelte/elements"; import type { HTMLLiAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLLiAttributes> = $props();
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLLiAttributes> = $props();
</script> </script>
<li <li
bind:this={ref} bind:this={ref}
data-slot="breadcrumb-item" data-slot="breadcrumb-item"
class={cn("inline-flex items-center gap-1.5", className)} class={cn("inline-flex items-center gap-1.5", className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</li> </li>
@@ -1,31 +1,31 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAnchorAttributes } from "svelte/elements"; import type { HTMLAnchorAttributes } from "svelte/elements";
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
href = undefined, href = undefined,
child, child,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAnchorAttributes> & { }: WithElementRef<HTMLAnchorAttributes> & {
child?: Snippet<[{ props: HTMLAnchorAttributes }]>; child?: Snippet<[{ props: HTMLAnchorAttributes }]>;
} = $props(); } = $props();
const attrs = $derived({ const attrs = $derived({
"data-slot": "breadcrumb-link", "data-slot": "breadcrumb-link",
class: cn("hover:text-foreground transition-colors", className), class: cn("hover:text-foreground transition-colors", className),
href, href,
...restProps, ...restProps
}); });
</script> </script>
{#if child} {#if child}
{@render child({ props: attrs })} {@render child({ props: attrs })}
{:else} {:else}
<a bind:this={ref} {...attrs}> <a bind:this={ref} {...attrs}>
{@render children?.()} {@render children?.()}
</a> </a>
{/if} {/if}
@@ -1,23 +1,15 @@
<script lang="ts"> <script lang="ts">
import type { HTMLOlAttributes } from "svelte/elements"; import type { HTMLOlAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLOlAttributes> = $props();
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLOlAttributes> = $props();
</script> </script>
<ol <ol
bind:this={ref} bind:this={ref}
data-slot="breadcrumb-list" data-slot="breadcrumb-list"
class={cn( class={cn("text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5", className)}
"text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5", {...restProps}
className
)}
{...restProps}
> >
{@render children?.()} {@render children?.()}
</ol> </ol>
@@ -1,23 +1,23 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();
</script> </script>
<span <span
bind:this={ref} bind:this={ref}
data-slot="breadcrumb-page" data-slot="breadcrumb-page"
role="link" role="link"
aria-disabled="true" aria-disabled="true"
aria-current="page" aria-current="page"
class={cn("text-foreground font-normal", className)} class={cn("text-foreground font-normal", className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</span> </span>
@@ -1,27 +1,22 @@
<script lang="ts"> <script lang="ts">
import ChevronRightIcon from "@lucide/svelte/icons/chevron-right"; import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLLiAttributes } from "svelte/elements"; import type { HTMLLiAttributes } from "svelte/elements";
let { let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLLiAttributes> = $props();
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLLiAttributes> = $props();
</script> </script>
<li <li
bind:this={ref} bind:this={ref}
data-slot="breadcrumb-separator" data-slot="breadcrumb-separator"
role="presentation" role="presentation"
aria-hidden="true" aria-hidden="true"
class={cn("[&>svg]:size-3.5", className)} class={cn("[&>svg]:size-3.5", className)}
{...restProps} {...restProps}
> >
{#if children} {#if children}
{@render children?.()} {@render children?.()}
{:else} {:else}
<ChevronRightIcon /> <ChevronRightIcon />
{/if} {/if}
</li> </li>
@@ -1,21 +1,15 @@
<script lang="ts"> <script lang="ts">
import type { WithElementRef } from "$lib/utils.js"; import type { WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLElement>> = $props();
</script> </script>
<nav <nav bind:this={ref} data-slot="breadcrumb" class={className} aria-label="breadcrumb" {...restProps}>
bind:this={ref} {@render children?.()}
data-slot="breadcrumb"
class={className}
aria-label="breadcrumb"
{...restProps}
>
{@render children?.()}
</nav> </nav>
+15 -15
View File
@@ -7,19 +7,19 @@ import List from "./breadcrumb-list.svelte";
import Page from "./breadcrumb-page.svelte"; import Page from "./breadcrumb-page.svelte";
export { export {
Root, Root,
Ellipsis, Ellipsis,
Item, Item,
Separator, Separator,
Link, Link,
List, List,
Page, Page,
// //
Root as Breadcrumb, Root as Breadcrumb,
Ellipsis as BreadcrumbEllipsis, Ellipsis as BreadcrumbEllipsis,
Item as BreadcrumbItem, Item as BreadcrumbItem,
Separator as BreadcrumbSeparator, Separator as BreadcrumbSeparator,
Link as BreadcrumbLink, Link as BreadcrumbLink,
List as BreadcrumbList, List as BreadcrumbList,
Page as BreadcrumbPage, Page as BreadcrumbPage,
}; };
@@ -1,20 +1,20 @@
<script lang="ts"> <script lang="ts">
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
import type { ComponentProps } from "svelte"; import type { ComponentProps } from "svelte";
import { Separator } from "$lib/components/ui/separator/index.js"; import { Separator } from "$lib/components/ui/separator/index.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
orientation = "vertical", orientation = "vertical",
...restProps ...restProps
}: ComponentProps<typeof Separator> = $props(); }: ComponentProps<typeof Separator> = $props();
</script> </script>
<Separator <Separator
bind:ref bind:ref
data-slot="button-group-separator" data-slot="button-group-separator"
{orientation} {orientation}
class={cn("bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto", className)} class={cn("bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto", className)}
{...restProps} {...restProps}
/> />
@@ -1,30 +1,30 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
child, child,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & { }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
child?: Snippet<[{ props: Record<string, unknown> }]>; child?: Snippet<[{ props: Record<string, unknown> }]>;
} = $props(); } = $props();
const mergedProps = $derived({ const mergedProps = $derived({
...restProps, ...restProps,
class: cn( class: cn(
"bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4", "bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
className className
), )
}); });
</script> </script>
{#if child} {#if child}
{@render child({ props: mergedProps })} {@render child({ props: mergedProps })}
{:else} {:else}
<div bind:this={ref} {...mergedProps}> <div bind:this={ref} {...mergedProps}>
{@render mergedProps.children?.()} {@render mergedProps.children?.()}
</div> </div>
{/if} {/if}
@@ -1,46 +1,46 @@
<script lang="ts" module> <script lang="ts" module>
import { tv, type VariantProps } from "tailwind-variants"; import { tv, type VariantProps } from "tailwind-variants";
export const buttonGroupVariants = tv({ export const buttonGroupVariants = tv({
base: "flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-2 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-e-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1", base: "flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-2 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-e-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
variants: { variants: {
orientation: { orientation: {
horizontal: horizontal:
"[&>*:not(:first-child)]:rounded-s-none [&>*:not(:first-child)]:border-s-0 [&>*:not(:last-child)]:rounded-e-none", "[&>*:not(:first-child)]:rounded-s-none [&>*:not(:first-child)]:border-s-0 [&>*:not(:last-child)]:rounded-e-none",
vertical: vertical:
"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none", "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none"
}, }
}, },
defaultVariants: { defaultVariants: {
orientation: "horizontal", orientation: "horizontal"
}, }
}); });
export type ButtonGroupOrientation = VariantProps<typeof buttonGroupVariants>["orientation"]; export type ButtonGroupOrientation = VariantProps<typeof buttonGroupVariants>["orientation"];
</script> </script>
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
orientation = "horizontal", orientation = "horizontal",
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & { }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
orientation?: ButtonGroupOrientation; orientation?: ButtonGroupOrientation;
} = $props(); } = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
role="group" role="group"
data-slot="button-group" data-slot="button-group"
data-orientation={orientation} data-orientation={orientation}
class={cn(buttonGroupVariants({ orientation }), className)} class={cn(buttonGroupVariants({ orientation }), className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
+7 -7
View File
@@ -3,11 +3,11 @@ import Text from "./button-group-text.svelte";
import Separator from "./button-group-separator.svelte"; import Separator from "./button-group-separator.svelte";
export { export {
Root, Root,
Text, Text,
Separator, Separator,
// //
Root as ButtonGroup, Root as ButtonGroup,
Text as ButtonGroupText, Text as ButtonGroupText,
Separator as ButtonGroupSeparator, Separator as ButtonGroupSeparator,
}; };
+70 -70
View File
@@ -1,82 +1,82 @@
<script lang="ts" module> <script lang="ts" module>
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from "svelte/elements"; import type { HTMLAnchorAttributes, HTMLButtonAttributes } from "svelte/elements";
import { type VariantProps, tv } from "tailwind-variants"; import { type VariantProps, tv } from "tailwind-variants";
export const buttonVariants = tv({ export const buttonVariants = tv({
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
variants: { variants: {
variant: { variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90 shadow-xs", default: "bg-primary text-primary-foreground hover:bg-primary/90 shadow-xs",
destructive: destructive:
"bg-destructive hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 text-white shadow-xs", "bg-destructive hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 text-white shadow-xs",
outline: outline:
"bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 border shadow-xs", "bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 border shadow-xs",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-xs", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-xs",
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline", link: "text-primary underline-offset-4 hover:underline"
}, },
size: { size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3", default: "h-9 px-4 py-2 has-[>svg]:px-3",
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5", sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4", lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
icon: "size-9", icon: "size-9",
"icon-sm": "size-8", "icon-sm": "size-8",
"icon-lg": "size-10", "icon-lg": "size-10"
}, }
}, },
defaultVariants: { defaultVariants: {
variant: "default", variant: "default",
size: "default", size: "default"
}, }
}); });
export type ButtonVariant = VariantProps<typeof buttonVariants>["variant"]; export type ButtonVariant = VariantProps<typeof buttonVariants>["variant"];
export type ButtonSize = VariantProps<typeof buttonVariants>["size"]; export type ButtonSize = VariantProps<typeof buttonVariants>["size"];
export type ButtonProps = WithElementRef<HTMLButtonAttributes> & export type ButtonProps = WithElementRef<HTMLButtonAttributes> &
WithElementRef<HTMLAnchorAttributes> & { WithElementRef<HTMLAnchorAttributes> & {
variant?: ButtonVariant; variant?: ButtonVariant;
size?: ButtonSize; size?: ButtonSize;
}; };
</script> </script>
<script lang="ts"> <script lang="ts">
let { let {
class: className, class: className,
variant = "default", variant = "default",
size = "default", size = "default",
ref = $bindable(null), ref = $bindable(null),
href = undefined, href = undefined,
type = "button", type = "button",
disabled, disabled,
children, children,
...restProps ...restProps
}: ButtonProps = $props(); }: ButtonProps = $props();
</script> </script>
{#if href} {#if href}
<a <a
bind:this={ref} bind:this={ref}
data-slot="button" data-slot="button"
class={cn(buttonVariants({ variant, size }), className)} class={cn(buttonVariants({ variant, size }), className)}
href={disabled ? undefined : href} href={disabled ? undefined : href}
aria-disabled={disabled} aria-disabled={disabled}
role={disabled ? "link" : undefined} role={disabled ? "link" : undefined}
tabindex={disabled ? -1 : undefined} tabindex={disabled ? -1 : undefined}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</a> </a>
{:else} {:else}
<button <button
bind:this={ref} bind:this={ref}
data-slot="button" data-slot="button"
class={cn(buttonVariants({ variant, size }), className)} class={cn(buttonVariants({ variant, size }), className)}
{type} {type}
{disabled} {disabled}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</button> </button>
{/if} {/if}
+9 -14
View File
@@ -1,17 +1,12 @@
import Root, { import Root, { type ButtonProps, type ButtonSize, type ButtonVariant, buttonVariants } from "./button.svelte";
type ButtonProps,
type ButtonSize,
type ButtonVariant,
buttonVariants,
} from "./button.svelte";
export { export {
Root, Root,
type ButtonProps as Props, type ButtonProps as Props,
// //
Root as Button, Root as Button,
buttonVariants, buttonVariants,
type ButtonProps, type ButtonProps,
type ButtonSize, type ButtonSize,
type ButtonVariant, type ButtonVariant,
}; };
+13 -13
View File
@@ -1,20 +1,20 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="card-action" data-slot="card-action"
class={cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className)} class={cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
@@ -1,15 +1,15 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div bind:this={ref} data-slot="card-content" class={cn("px-6", className)} {...restProps}> <div bind:this={ref} data-slot="card-content" class={cn("px-6", className)} {...restProps}>
{@render children?.()} {@render children?.()}
</div> </div>
@@ -1,20 +1,15 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLParagraphElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLParagraphElement>> = $props();
</script> </script>
<p <p bind:this={ref} data-slot="card-description" class={cn("text-muted-foreground text-sm", className)} {...restProps}>
bind:this={ref} {@render children?.()}
data-slot="card-description"
class={cn("text-muted-foreground text-sm", className)}
{...restProps}
>
{@render children?.()}
</p> </p>
+13 -13
View File
@@ -1,20 +1,20 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="card-footer" data-slot="card-footer"
class={cn("flex items-center px-6 [.border-t]:pt-6", className)} class={cn("flex items-center px-6 [.border-t]:pt-6", className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
+16 -16
View File
@@ -1,23 +1,23 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="card-header" data-slot="card-header"
class={cn( class={cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
className className
)} )}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
+10 -15
View File
@@ -1,20 +1,15 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div bind:this={ref} data-slot="card-title" class={cn("leading-none font-semibold", className)} {...restProps}>
bind:this={ref} {@render children?.()}
data-slot="card-title"
class={cn("leading-none font-semibold", className)}
{...restProps}
>
{@render children?.()}
</div> </div>
+13 -16
View File
@@ -1,23 +1,20 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="card" data-slot="card"
class={cn( class={cn("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", className)}
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", {...restProps}
className
)}
{...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
+15 -15
View File
@@ -7,19 +7,19 @@ import Title from "./card-title.svelte";
import Action from "./card-action.svelte"; import Action from "./card-action.svelte";
export { export {
Root, Root,
Content, Content,
Description, Description,
Footer, Footer,
Header, Header,
Title, Title,
Action, Action,
// //
Root as Card, Root as Card,
Content as CardContent, Content as CardContent,
Description as CardDescription, Description as CardDescription,
Footer as CardFooter, Footer as CardFooter,
Header as CardHeader, Header as CardHeader,
Title as CardTitle, Title as CardTitle,
Action as CardAction, Action as CardAction,
}; };
@@ -1,80 +1,80 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import ChartStyle from "./chart-style.svelte"; import ChartStyle from "./chart-style.svelte";
import { setChartContext, type ChartConfig } from "./chart-utils.js"; import { setChartContext, type ChartConfig } from "./chart-utils.js";
const uid = $props.id(); const uid = $props.id();
let { let {
ref = $bindable(null), ref = $bindable(null),
id = uid, id = uid,
class: className, class: className,
children, children,
config, config,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLElement>> & { }: WithElementRef<HTMLAttributes<HTMLElement>> & {
config: ChartConfig; config: ChartConfig;
} = $props(); } = $props();
const chartId = `chart-${id || uid.replace(/:/g, "")}`; const chartId = `chart-${id || uid.replace(/:/g, "")}`;
setChartContext({ setChartContext({
get config() { get config() {
return config; return config;
}, }
}); });
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-chart={chartId} data-chart={chartId}
data-slot="chart" data-slot="chart"
class={cn( class={cn(
"flex aspect-video justify-center overflow-visible text-xs", "flex aspect-video justify-center overflow-visible text-xs",
// Overrides // Overrides
// //
// Stroke around dots/marks when hovering // Stroke around dots/marks when hovering
"[&_.lc-highlight-point]:stroke-transparent", "[&_.lc-highlight-point]:stroke-transparent",
// override the default stroke color of lines // override the default stroke color of lines
"[&_.lc-line]:stroke-border/50", "[&_.lc-line]:stroke-border/50",
// by default, layerchart shows a line intersecting the point when hovering, this hides that // by default, layerchart shows a line intersecting the point when hovering, this hides that
"[&_.lc-highlight-line]:stroke-0", "[&_.lc-highlight-line]:stroke-0",
// by default, when you hover a point on a stacked series chart, it will drop the opacity // by default, when you hover a point on a stacked series chart, it will drop the opacity
// of the other series, this overrides that // of the other series, this overrides that
"[&_.lc-area-path]:opacity-100 [&_.lc-highlight-line]:opacity-100 [&_.lc-highlight-point]:opacity-100 [&_.lc-spline-path]:opacity-100 [&_.lc-text]:text-xs [&_.lc-text-svg]:overflow-visible", "[&_.lc-area-path]:opacity-100 [&_.lc-highlight-line]:opacity-100 [&_.lc-highlight-point]:opacity-100 [&_.lc-spline-path]:opacity-100 [&_.lc-text]:text-xs [&_.lc-text-svg]:overflow-visible",
// We don't want the little tick lines between the axis labels and the chart, so we remove // We don't want the little tick lines between the axis labels and the chart, so we remove
// the stroke. The alternative is to manually disable `tickMarks` on the x/y axis of every // the stroke. The alternative is to manually disable `tickMarks` on the x/y axis of every
// chart. // chart.
"[&_.lc-axis-tick]:stroke-0", "[&_.lc-axis-tick]:stroke-0",
// We don't want to display the rule on the x/y axis, as there is already going to be // We don't want to display the rule on the x/y axis, as there is already going to be
// a grid line there and rule ends up overlapping the marks because it is rendered after // a grid line there and rule ends up overlapping the marks because it is rendered after
// the marks // the marks
"[&_.lc-rule-x-line:not(.lc-grid-x-rule)]:stroke-0 [&_.lc-rule-y-line:not(.lc-grid-y-rule)]:stroke-0", "[&_.lc-rule-x-line:not(.lc-grid-x-rule)]:stroke-0 [&_.lc-rule-y-line:not(.lc-grid-y-rule)]:stroke-0",
"[&_.lc-grid-x-radial-line]:stroke-border [&_.lc-grid-x-radial-circle]:stroke-border", "[&_.lc-grid-x-radial-line]:stroke-border [&_.lc-grid-x-radial-circle]:stroke-border",
"[&_.lc-grid-y-radial-line]:stroke-border [&_.lc-grid-y-radial-circle]:stroke-border", "[&_.lc-grid-y-radial-line]:stroke-border [&_.lc-grid-y-radial-circle]:stroke-border",
// Legend adjustments // Legend adjustments
"[&_.lc-legend-swatch-button]:items-center [&_.lc-legend-swatch-button]:gap-1.5", "[&_.lc-legend-swatch-button]:items-center [&_.lc-legend-swatch-button]:gap-1.5",
"[&_.lc-legend-swatch-group]:items-center [&_.lc-legend-swatch-group]:gap-4", "[&_.lc-legend-swatch-group]:items-center [&_.lc-legend-swatch-group]:gap-4",
"[&_.lc-legend-swatch]:size-2.5 [&_.lc-legend-swatch]:rounded-[2px]", "[&_.lc-legend-swatch]:size-2.5 [&_.lc-legend-swatch]:rounded-[2px]",
// Labels // Labels
"[&_.lc-labels-text:not([fill])]:fill-foreground [&_text]:stroke-transparent", "[&_.lc-labels-text:not([fill])]:fill-foreground [&_text]:stroke-transparent",
// Tick labels on th x/y axes // Tick labels on th x/y axes
"[&_.lc-axis-tick-label]:fill-muted-foreground [&_.lc-axis-tick-label]:font-normal", "[&_.lc-axis-tick-label]:fill-muted-foreground [&_.lc-axis-tick-label]:font-normal",
"[&_.lc-tooltip-rects-g]:fill-transparent", "[&_.lc-tooltip-rects-g]:fill-transparent",
"[&_.lc-layout-svg-g]:fill-transparent", "[&_.lc-layout-svg-g]:fill-transparent",
"[&_.lc-root-container]:w-full", "[&_.lc-root-container]:w-full",
className className
)} )}
{...restProps} {...restProps}
> >
<ChartStyle id={chartId} {config} /> <ChartStyle id={chartId} {config} />
{@render children?.()} {@render children?.()}
</div> </div>
+25 -25
View File
@@ -1,37 +1,37 @@
<script lang="ts"> <script lang="ts">
import { THEMES, type ChartConfig } from "./chart-utils.js"; import { THEMES, type ChartConfig } from "./chart-utils.js";
let { id, config }: { id: string; config: ChartConfig } = $props(); let { id, config }: { id: string; config: ChartConfig } = $props();
const colorConfig = $derived( const colorConfig = $derived(
config ? Object.entries(config).filter(([, config]) => config.theme || config.color) : null config ? Object.entries(config).filter(([, config]) => config.theme || config.color) : null
); );
const themeContents = $derived.by(() => { const themeContents = $derived.by(() => {
if (!colorConfig || !colorConfig.length) return; if (!colorConfig || !colorConfig.length) return;
const themeContents = []; const themeContents = [];
for (let [_theme, prefix] of Object.entries(THEMES)) { for (let [_theme, prefix] of Object.entries(THEMES)) {
let content = `${prefix} [data-chart=${id}] {\n`; let content = `${prefix} [data-chart=${id}] {\n`;
const color = colorConfig.map(([key, itemConfig]) => { const color = colorConfig.map(([key, itemConfig]) => {
const theme = _theme as keyof typeof itemConfig.theme; const theme = _theme as keyof typeof itemConfig.theme;
const color = itemConfig.theme?.[theme] || itemConfig.color; const color = itemConfig.theme?.[theme] || itemConfig.color;
return color ? `\t--color-${key}: ${color};` : null; return color ? `\t--color-${key}: ${color};` : null;
}); });
content += color.join("\n") + "\n}"; content += color.join("\n") + "\n}";
themeContents.push(content); themeContents.push(content);
} }
return themeContents.join("\n"); return themeContents.join("\n");
}); });
</script> </script>
{#if themeContents} {#if themeContents}
{#key id} {#key id}
<svelte:element this={"style"}> <svelte:element this={"style"}>
{themeContents} {themeContents}
</svelte:element> </svelte:element>
{/key} {/key}
{/if} {/if}
+135 -142
View File
@@ -1,159 +1,152 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef, type WithoutChildren } from "$lib/utils.js"; import { cn, type WithElementRef, type WithoutChildren } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { getPayloadConfigFromPayload, useChart, type TooltipPayload } from "./chart-utils.js"; import { getPayloadConfigFromPayload, useChart, type TooltipPayload } from "./chart-utils.js";
import { getTooltipContext, Tooltip as TooltipPrimitive } from "layerchart"; import { getTooltipContext, Tooltip as TooltipPrimitive } from "layerchart";
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
function defaultFormatter(value: any, _payload: TooltipPayload[]) { function defaultFormatter(value: any, _payload: TooltipPayload[]) {
return `${value}`; return `${value}`;
} }
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
hideLabel = false, hideLabel = false,
indicator = "dot", indicator = "dot",
hideIndicator = false, hideIndicator = false,
labelKey, labelKey,
label, label,
labelFormatter = defaultFormatter, labelFormatter = defaultFormatter,
labelClassName, labelClassName,
formatter, formatter,
nameKey, nameKey,
color, color,
...restProps ...restProps
}: WithoutChildren<WithElementRef<HTMLAttributes<HTMLDivElement>>> & { }: WithoutChildren<WithElementRef<HTMLAttributes<HTMLDivElement>>> & {
hideLabel?: boolean; hideLabel?: boolean;
label?: string; label?: string;
indicator?: "line" | "dot" | "dashed"; indicator?: "line" | "dot" | "dashed";
nameKey?: string; nameKey?: string;
labelKey?: string; labelKey?: string;
hideIndicator?: boolean; hideIndicator?: boolean;
labelClassName?: string; labelClassName?: string;
labelFormatter?: // eslint-disable-next-line @typescript-eslint/no-explicit-any labelFormatter?: // eslint-disable-next-line @typescript-eslint/no-explicit-any
((value: any, payload: TooltipPayload[]) => string | number | Snippet) | null; ((value: any, payload: TooltipPayload[]) => string | number | Snippet) | null;
formatter?: Snippet< formatter?: Snippet<
[ [
{ {
value: unknown; value: unknown;
name: string; name: string;
item: TooltipPayload; item: TooltipPayload;
index: number; index: number;
payload: TooltipPayload[]; payload: TooltipPayload[];
}, }
] ]
>; >;
} = $props(); } = $props();
const chart = useChart(); const chart = useChart();
const tooltipCtx = getTooltipContext(); const tooltipCtx = getTooltipContext();
const formattedLabel = $derived.by(() => { const formattedLabel = $derived.by(() => {
if (hideLabel || !tooltipCtx.payload?.length) return null; if (hideLabel || !tooltipCtx.payload?.length) return null;
const [item] = tooltipCtx.payload; const [item] = tooltipCtx.payload;
const key = labelKey ?? item?.label ?? item?.name ?? "value"; const key = labelKey ?? item?.label ?? item?.name ?? "value";
const itemConfig = getPayloadConfigFromPayload(chart.config, item, key); const itemConfig = getPayloadConfigFromPayload(chart.config, item, key);
const value = const value =
!labelKey && typeof label === "string" !labelKey && typeof label === "string"
? (chart.config[label as keyof typeof chart.config]?.label ?? label) ? (chart.config[label as keyof typeof chart.config]?.label ?? label)
: (itemConfig?.label ?? item.label); : (itemConfig?.label ?? item.label);
if (value === undefined) return null; if (value === undefined) return null;
if (!labelFormatter) return value; if (!labelFormatter) return value;
return labelFormatter(value, tooltipCtx.payload); return labelFormatter(value, tooltipCtx.payload);
}); });
const nestLabel = $derived(tooltipCtx.payload.length === 1 && indicator !== "dot"); const nestLabel = $derived(tooltipCtx.payload.length === 1 && indicator !== "dot");
</script> </script>
{#snippet TooltipLabel()} {#snippet TooltipLabel()}
{#if formattedLabel} {#if formattedLabel}
<div class={cn("font-medium", labelClassName)}> <div class={cn("font-medium", labelClassName)}>
{#if typeof formattedLabel === "function"} {#if typeof formattedLabel === "function"}
{@render formattedLabel()} {@render formattedLabel()}
{:else} {:else}
{formattedLabel} {formattedLabel}
{/if} {/if}
</div> </div>
{/if} {/if}
{/snippet} {/snippet}
<TooltipPrimitive.Root variant="none"> <TooltipPrimitive.Root variant="none">
<div <div
class={cn( class={cn(
"border-border/50 bg-background grid min-w-[9rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl", "border-border/50 bg-background grid min-w-[9rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl",
className className
)} )}
{...restProps} {...restProps}
> >
{#if !nestLabel} {#if !nestLabel}
{@render TooltipLabel()} {@render TooltipLabel()}
{/if} {/if}
<div class="grid gap-1.5"> <div class="grid gap-1.5">
{#each tooltipCtx.payload as item, i (item.key + i)} {#each tooltipCtx.payload as item, i (item.key + i)}
{@const key = `${nameKey || item.key || item.name || "value"}`} {@const key = `${nameKey || item.key || item.name || "value"}`}
{@const itemConfig = getPayloadConfigFromPayload(chart.config, item, key)} {@const itemConfig = getPayloadConfigFromPayload(chart.config, item, key)}
{@const indicatorColor = color || item.payload?.color || item.color} {@const indicatorColor = color || item.payload?.color || item.color}
<div <div
class={cn( class={cn(
"[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:size-2.5", "[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:size-2.5",
indicator === "dot" && "items-center" indicator === "dot" && "items-center"
)} )}
> >
{#if formatter && item.value !== undefined && item.name} {#if formatter && item.value !== undefined && item.name}
{@render formatter({ {@render formatter({
value: item.value, value: item.value,
name: item.name, name: item.name,
item, item,
index: i, index: i,
payload: tooltipCtx.payload, payload: tooltipCtx.payload
})} })}
{:else} {:else}
{#if itemConfig?.icon} {#if itemConfig?.icon}
<itemConfig.icon /> <itemConfig.icon />
{:else if !hideIndicator} {:else if !hideIndicator}
<div <div
style="--color-bg: {indicatorColor}; --color-border: {indicatorColor};" style="--color-bg: {indicatorColor}; --color-border: {indicatorColor};"
class={cn( class={cn("shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)", {
"shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)", "size-2.5": indicator === "dot",
{ "h-full w-1": indicator === "line",
"size-2.5": indicator === "dot", "w-0 border-[1.5px] border-dashed bg-transparent": indicator === "dashed",
"h-full w-1": indicator === "line", "my-0.5": nestLabel && indicator === "dashed"
"w-0 border-[1.5px] border-dashed bg-transparent": })}
indicator === "dashed", ></div>
"my-0.5": nestLabel && indicator === "dashed", {/if}
} <div
)} class={cn("flex flex-1 shrink-0 justify-between leading-none", nestLabel ? "items-end" : "items-center")}
></div> >
{/if} <div class="grid gap-1.5">
<div {#if nestLabel}
class={cn( {@render TooltipLabel()}
"flex flex-1 shrink-0 justify-between leading-none", {/if}
nestLabel ? "items-end" : "items-center" <span class="text-muted-foreground">
)} {itemConfig?.label || item.name}
> </span>
<div class="grid gap-1.5"> </div>
{#if nestLabel} {#if item.value !== undefined}
{@render TooltipLabel()} <span class="text-foreground font-mono font-medium tabular-nums">
{/if} {item.value.toLocaleString()}
<span class="text-muted-foreground"> </span>
{itemConfig?.label || item.name} {/if}
</span> </div>
</div> {/if}
{#if item.value !== undefined} </div>
<span class="text-foreground font-mono font-medium tabular-nums"> {/each}
{item.value.toLocaleString()} </div>
</span> </div>
{/if}
</div>
{/if}
</div>
{/each}
</div>
</div>
</TooltipPrimitive.Root> </TooltipPrimitive.Root>
+29 -38
View File
@@ -4,63 +4,54 @@ import { getContext, setContext, type Component, type ComponentProps, type Snipp
export const THEMES = { light: "", dark: ".dark" } as const; export const THEMES = { light: "", dark: ".dark" } as const;
export type ChartConfig = { export type ChartConfig = {
[k in string]: { [k in string]: {
label?: string; label?: string;
icon?: Component; icon?: Component;
} & ( } & ({ color?: string; theme?: never } | { color?: never; theme: Record<keyof typeof THEMES, string> });
| { color?: string; theme?: never }
| { color?: never; theme: Record<keyof typeof THEMES, string> }
);
}; };
export type ExtractSnippetParams<T> = T extends Snippet<[infer P]> ? P : never; export type ExtractSnippetParams<T> = T extends Snippet<[infer P]> ? P : never;
export type TooltipPayload = ExtractSnippetParams< export type TooltipPayload = ExtractSnippetParams<ComponentProps<typeof Tooltip.Root>["children"]>["payload"][number];
ComponentProps<typeof Tooltip.Root>["children"]
>["payload"][number];
// Helper to extract item config from a payload. // Helper to extract item config from a payload.
export function getPayloadConfigFromPayload( export function getPayloadConfigFromPayload(config: ChartConfig, payload: TooltipPayload, key: string) {
config: ChartConfig, if (typeof payload !== "object" || payload === null) return undefined;
payload: TooltipPayload,
key: string
) {
if (typeof payload !== "object" || payload === null) return undefined;
const payloadPayload = const payloadPayload =
"payload" in payload && typeof payload.payload === "object" && payload.payload !== null "payload" in payload && typeof payload.payload === "object" && payload.payload !== null
? payload.payload ? payload.payload
: undefined; : undefined;
let configLabelKey: string = key; let configLabelKey: string = key;
if (payload.key === key) { if (payload.key === key) {
configLabelKey = payload.key; configLabelKey = payload.key;
} else if (payload.name === key) { } else if (payload.name === key) {
configLabelKey = payload.name; configLabelKey = payload.name;
} else if (key in payload && typeof payload[key as keyof typeof payload] === "string") { } else if (key in payload && typeof payload[key as keyof typeof payload] === "string") {
configLabelKey = payload[key as keyof typeof payload] as string; configLabelKey = payload[key as keyof typeof payload] as string;
} else if ( } else if (
payloadPayload !== undefined && payloadPayload !== undefined &&
key in payloadPayload && key in payloadPayload &&
typeof payloadPayload[key as keyof typeof payloadPayload] === "string" typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
) { ) {
configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string; configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string;
} }
return configLabelKey in config ? config[configLabelKey] : config[key as keyof typeof config]; return configLabelKey in config ? config[configLabelKey] : config[key as keyof typeof config];
} }
type ChartContextValue = { type ChartContextValue = {
config: ChartConfig; config: ChartConfig;
}; };
const chartContextKey = Symbol("chart-context"); const chartContextKey = Symbol("chart-context");
export function setChartContext(value: ChartContextValue) { export function setChartContext(value: ChartContextValue) {
return setContext(chartContextKey, value); return setContext(chartContextKey, value);
} }
export function useChart() { export function useChart() {
return getContext<ChartContextValue>(chartContextKey); return getContext<ChartContextValue>(chartContextKey);
} }
+29 -29
View File
@@ -1,36 +1,36 @@
<script lang="ts"> <script lang="ts">
import { Checkbox as CheckboxPrimitive } from "bits-ui"; import { Checkbox as CheckboxPrimitive } from "bits-ui";
import CheckIcon from "@lucide/svelte/icons/check"; import CheckIcon from "@lucide/svelte/icons/check";
import MinusIcon from "@lucide/svelte/icons/minus"; import MinusIcon from "@lucide/svelte/icons/minus";
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js"; import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
checked = $bindable(false), checked = $bindable(false),
indeterminate = $bindable(false), indeterminate = $bindable(false),
class: className, class: className,
...restProps ...restProps
}: WithoutChildrenOrChild<CheckboxPrimitive.RootProps> = $props(); }: WithoutChildrenOrChild<CheckboxPrimitive.RootProps> = $props();
</script> </script>
<CheckboxPrimitive.Root <CheckboxPrimitive.Root
bind:ref bind:ref
data-slot="checkbox" data-slot="checkbox"
class={cn( class={cn(
"border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive peer flex size-4 shrink-0 items-center justify-center rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50", "border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive peer flex size-4 shrink-0 items-center justify-center rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
className className
)} )}
bind:checked bind:checked
bind:indeterminate bind:indeterminate
{...restProps} {...restProps}
> >
{#snippet children({ checked, indeterminate })} {#snippet children({ checked, indeterminate })}
<div data-slot="checkbox-indicator" class="text-current transition-none"> <div data-slot="checkbox-indicator" class="text-current transition-none">
{#if checked} {#if checked}
<CheckIcon class="size-3.5" /> <CheckIcon class="size-3.5" />
{:else if indeterminate} {:else if indeterminate}
<MinusIcon class="size-3.5" /> <MinusIcon class="size-3.5" />
{/if} {/if}
</div> </div>
{/snippet} {/snippet}
</CheckboxPrimitive.Root> </CheckboxPrimitive.Root>
+3 -3
View File
@@ -1,6 +1,6 @@
import Root from "./checkbox.svelte"; import Root from "./checkbox.svelte";
export { export {
Root, Root,
// //
Root as Checkbox, Root as Checkbox,
}; };
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui"; import { Dialog as DialogPrimitive } from "bits-ui";
let { ref = $bindable(null), ...restProps }: DialogPrimitive.CloseProps = $props(); let { ref = $bindable(null), ...restProps }: DialogPrimitive.CloseProps = $props();
</script> </script>
<DialogPrimitive.Close bind:ref data-slot="dialog-close" {...restProps} /> <DialogPrimitive.Close bind:ref data-slot="dialog-close" {...restProps} />
@@ -1,45 +1,45 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui"; import { Dialog as DialogPrimitive } from "bits-ui";
import DialogPortal from "./dialog-portal.svelte"; import DialogPortal from "./dialog-portal.svelte";
import XIcon from "@lucide/svelte/icons/x"; import XIcon from "@lucide/svelte/icons/x";
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
import * as Dialog from "./index.js"; import * as Dialog from "./index.js";
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js"; import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
import type { ComponentProps } from "svelte"; import type { ComponentProps } from "svelte";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
portalProps, portalProps,
children, children,
showCloseButton = true, showCloseButton = true,
...restProps ...restProps
}: WithoutChildrenOrChild<DialogPrimitive.ContentProps> & { }: WithoutChildrenOrChild<DialogPrimitive.ContentProps> & {
portalProps?: WithoutChildrenOrChild<ComponentProps<typeof DialogPortal>>; portalProps?: WithoutChildrenOrChild<ComponentProps<typeof DialogPortal>>;
children: Snippet; children: Snippet;
showCloseButton?: boolean; showCloseButton?: boolean;
} = $props(); } = $props();
</script> </script>
<DialogPortal {...portalProps}> <DialogPortal {...portalProps}>
<Dialog.Overlay /> <Dialog.Overlay />
<DialogPrimitive.Content <DialogPrimitive.Content
bind:ref bind:ref
data-slot="dialog-content" data-slot="dialog-content"
class={cn( class={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg", "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
className className
)} )}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
{#if showCloseButton} {#if showCloseButton}
<DialogPrimitive.Close <DialogPrimitive.Close
class="ring-offset-background focus:ring-ring absolute end-4 top-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4" class="ring-offset-background focus:ring-ring absolute end-4 top-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
> >
<XIcon /> <XIcon />
<span class="sr-only">Close</span> <span class="sr-only">Close</span>
</DialogPrimitive.Close> </DialogPrimitive.Close>
{/if} {/if}
</DialogPrimitive.Content> </DialogPrimitive.Content>
</DialogPortal> </DialogPortal>
@@ -1,17 +1,13 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui"; import { Dialog as DialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
let { let { ref = $bindable(null), class: className, ...restProps }: DialogPrimitive.DescriptionProps = $props();
ref = $bindable(null),
class: className,
...restProps
}: DialogPrimitive.DescriptionProps = $props();
</script> </script>
<DialogPrimitive.Description <DialogPrimitive.Description
bind:ref bind:ref
data-slot="dialog-description" data-slot="dialog-description"
class={cn("text-muted-foreground text-sm", className)} class={cn("text-muted-foreground text-sm", className)}
{...restProps} {...restProps}
/> />
@@ -1,20 +1,20 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="dialog-footer" data-slot="dialog-footer"
class={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)} class={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
@@ -1,20 +1,20 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="dialog-header" data-slot="dialog-header"
class={cn("flex flex-col gap-2 text-center sm:text-start", className)} class={cn("flex flex-col gap-2 text-center sm:text-start", className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
@@ -1,20 +1,16 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui"; import { Dialog as DialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
let { let { ref = $bindable(null), class: className, ...restProps }: DialogPrimitive.OverlayProps = $props();
ref = $bindable(null),
class: className,
...restProps
}: DialogPrimitive.OverlayProps = $props();
</script> </script>
<DialogPrimitive.Overlay <DialogPrimitive.Overlay
bind:ref bind:ref
data-slot="dialog-overlay" data-slot="dialog-overlay"
class={cn( class={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
className className
)} )}
{...restProps} {...restProps}
/> />
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui"; import { Dialog as DialogPrimitive } from "bits-ui";
let { ...restProps }: DialogPrimitive.PortalProps = $props(); let { ...restProps }: DialogPrimitive.PortalProps = $props();
</script> </script>
<DialogPrimitive.Portal {...restProps} /> <DialogPrimitive.Portal {...restProps} />
@@ -1,17 +1,13 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui"; import { Dialog as DialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
let { let { ref = $bindable(null), class: className, ...restProps }: DialogPrimitive.TitleProps = $props();
ref = $bindable(null),
class: className,
...restProps
}: DialogPrimitive.TitleProps = $props();
</script> </script>
<DialogPrimitive.Title <DialogPrimitive.Title
bind:ref bind:ref
data-slot="dialog-title" data-slot="dialog-title"
class={cn("text-lg leading-none font-semibold", className)} class={cn("text-lg leading-none font-semibold", className)}
{...restProps} {...restProps}
/> />
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui"; import { Dialog as DialogPrimitive } from "bits-ui";
let { ref = $bindable(null), ...restProps }: DialogPrimitive.TriggerProps = $props(); let { ref = $bindable(null), ...restProps }: DialogPrimitive.TriggerProps = $props();
</script> </script>
<DialogPrimitive.Trigger bind:ref data-slot="dialog-trigger" {...restProps} /> <DialogPrimitive.Trigger bind:ref data-slot="dialog-trigger" {...restProps} />
+2 -2
View File
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui"; import { Dialog as DialogPrimitive } from "bits-ui";
let { open = $bindable(false), ...restProps }: DialogPrimitive.RootProps = $props(); let { open = $bindable(false), ...restProps }: DialogPrimitive.RootProps = $props();
</script> </script>
<DialogPrimitive.Root bind:open {...restProps} /> <DialogPrimitive.Root bind:open {...restProps} />
+21 -21
View File
@@ -10,25 +10,25 @@ import Trigger from "./dialog-trigger.svelte";
import Close from "./dialog-close.svelte"; import Close from "./dialog-close.svelte";
export { export {
Root, Root,
Title, Title,
Portal, Portal,
Footer, Footer,
Header, Header,
Trigger, Trigger,
Overlay, Overlay,
Content, Content,
Description, Description,
Close, Close,
// //
Root as Dialog, Root as Dialog,
Title as DialogTitle, Title as DialogTitle,
Portal as DialogPortal, Portal as DialogPortal,
Footer as DialogFooter, Footer as DialogFooter,
Header as DialogHeader, Header as DialogHeader,
Trigger as DialogTrigger, Trigger as DialogTrigger,
Overlay as DialogOverlay, Overlay as DialogOverlay,
Content as DialogContent, Content as DialogContent,
Description as DialogDescription, Description as DialogDescription,
Close as DialogClose, Close as DialogClose,
}; };
@@ -1,16 +1,11 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { let {
ref = $bindable(null), ref = $bindable(null),
value = $bindable([]), value = $bindable([]),
...restProps ...restProps
}: DropdownMenuPrimitive.CheckboxGroupProps = $props(); }: DropdownMenuPrimitive.CheckboxGroupProps = $props();
</script> </script>
<DropdownMenuPrimitive.CheckboxGroup <DropdownMenuPrimitive.CheckboxGroup bind:ref bind:value data-slot="dropdown-menu-checkbox-group" {...restProps} />
bind:ref
bind:value
data-slot="dropdown-menu-checkbox-group"
{...restProps}
/>
@@ -1,43 +1,41 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import CheckIcon from "@lucide/svelte/icons/check"; import CheckIcon from "@lucide/svelte/icons/check";
import MinusIcon from "@lucide/svelte/icons/minus"; import MinusIcon from "@lucide/svelte/icons/minus";
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js"; import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
let { let {
ref = $bindable(null), ref = $bindable(null),
checked = $bindable(false), checked = $bindable(false),
indeterminate = $bindable(false), indeterminate = $bindable(false),
class: className, class: className,
children: childrenProp, children: childrenProp,
...restProps ...restProps
}: WithoutChildrenOrChild<DropdownMenuPrimitive.CheckboxItemProps> & { }: WithoutChildrenOrChild<DropdownMenuPrimitive.CheckboxItemProps> & {
children?: Snippet; children?: Snippet;
} = $props(); } = $props();
</script> </script>
<DropdownMenuPrimitive.CheckboxItem <DropdownMenuPrimitive.CheckboxItem
bind:ref bind:ref
bind:checked bind:checked
bind:indeterminate bind:indeterminate
data-slot="dropdown-menu-checkbox-item" data-slot="dropdown-menu-checkbox-item"
class={cn( class={cn(
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 ps-8 pe-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 ps-8 pe-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
{...restProps} {...restProps}
> >
{#snippet children({ checked, indeterminate })} {#snippet children({ checked, indeterminate })}
<span <span class="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center">
class="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center" {#if indeterminate}
> <MinusIcon class="size-4" />
{#if indeterminate} {:else}
<MinusIcon class="size-4" /> <CheckIcon class={cn("size-4", !checked && "text-transparent")} />
{:else} {/if}
<CheckIcon class={cn("size-4", !checked && "text-transparent")} /> </span>
{/if} {@render childrenProp?.()}
</span> {/snippet}
{@render childrenProp?.()}
{/snippet}
</DropdownMenuPrimitive.CheckboxItem> </DropdownMenuPrimitive.CheckboxItem>
@@ -1,29 +1,29 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js"; import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
import DropdownMenuPortal from "./dropdown-menu-portal.svelte"; import DropdownMenuPortal from "./dropdown-menu-portal.svelte";
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import type { ComponentProps } from "svelte"; import type { ComponentProps } from "svelte";
let { let {
ref = $bindable(null), ref = $bindable(null),
sideOffset = 4, sideOffset = 4,
portalProps, portalProps,
class: className, class: className,
...restProps ...restProps
}: DropdownMenuPrimitive.ContentProps & { }: DropdownMenuPrimitive.ContentProps & {
portalProps?: WithoutChildrenOrChild<ComponentProps<typeof DropdownMenuPortal>>; portalProps?: WithoutChildrenOrChild<ComponentProps<typeof DropdownMenuPortal>>;
} = $props(); } = $props();
</script> </script>
<DropdownMenuPortal {...portalProps}> <DropdownMenuPortal {...portalProps}>
<DropdownMenuPrimitive.Content <DropdownMenuPrimitive.Content
bind:ref bind:ref
data-slot="dropdown-menu-content" data-slot="dropdown-menu-content"
{sideOffset} {sideOffset}
class={cn( class={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-end-2 data-[side=right]:slide-in-from-start-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--bits-dropdown-menu-content-available-height) min-w-[8rem] origin-(--bits-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md outline-none", "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-end-2 data-[side=right]:slide-in-from-start-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--bits-dropdown-menu-content-available-height) min-w-[8rem] origin-(--bits-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md outline-none",
className className
)} )}
{...restProps} {...restProps}
/> />
</DropdownMenuPortal> </DropdownMenuPortal>
@@ -1,22 +1,22 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
import type { ComponentProps } from "svelte"; import type { ComponentProps } from "svelte";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
inset, inset,
...restProps ...restProps
}: ComponentProps<typeof DropdownMenuPrimitive.GroupHeading> & { }: ComponentProps<typeof DropdownMenuPrimitive.GroupHeading> & {
inset?: boolean; inset?: boolean;
} = $props(); } = $props();
</script> </script>
<DropdownMenuPrimitive.GroupHeading <DropdownMenuPrimitive.GroupHeading
bind:ref bind:ref
data-slot="dropdown-menu-group-heading" data-slot="dropdown-menu-group-heading"
data-inset={inset} data-inset={inset}
class={cn("px-2 py-1.5 text-sm font-semibold data-[inset]:ps-8", className)} class={cn("px-2 py-1.5 text-sm font-semibold data-[inset]:ps-8", className)}
{...restProps} {...restProps}
/> />
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.GroupProps = $props(); let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.GroupProps = $props();
</script> </script>
<DropdownMenuPrimitive.Group bind:ref data-slot="dropdown-menu-group" {...restProps} /> <DropdownMenuPrimitive.Group bind:ref data-slot="dropdown-menu-group" {...restProps} />
@@ -1,27 +1,27 @@
<script lang="ts"> <script lang="ts">
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
inset, inset,
variant = "default", variant = "default",
...restProps ...restProps
}: DropdownMenuPrimitive.ItemProps & { }: DropdownMenuPrimitive.ItemProps & {
inset?: boolean; inset?: boolean;
variant?: "default" | "destructive"; variant?: "default" | "destructive";
} = $props(); } = $props();
</script> </script>
<DropdownMenuPrimitive.Item <DropdownMenuPrimitive.Item
bind:ref bind:ref
data-slot="dropdown-menu-item" data-slot="dropdown-menu-item"
data-inset={inset} data-inset={inset}
data-variant={variant} data-variant={variant}
class={cn( class={cn(
"data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:data-highlighted:bg-destructive/10 dark:data-[variant=destructive]:data-highlighted:bg-destructive/20 data-[variant=destructive]:data-highlighted:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:ps-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:data-highlighted:bg-destructive/10 dark:data-[variant=destructive]:data-highlighted:bg-destructive/20 data-[variant=destructive]:data-highlighted:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:ps-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
{...restProps} {...restProps}
/> />
@@ -1,24 +1,24 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
inset, inset,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & { }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
inset?: boolean; inset?: boolean;
} = $props(); } = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="dropdown-menu-label" data-slot="dropdown-menu-label"
data-inset={inset} data-inset={inset}
class={cn("px-2 py-1.5 text-sm font-semibold data-[inset]:ps-8", className)} class={cn("px-2 py-1.5 text-sm font-semibold data-[inset]:ps-8", className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { ...restProps }: DropdownMenuPrimitive.PortalProps = $props(); let { ...restProps }: DropdownMenuPrimitive.PortalProps = $props();
</script> </script>
<DropdownMenuPrimitive.Portal {...restProps} /> <DropdownMenuPrimitive.Portal {...restProps} />
@@ -1,16 +1,7 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { let { ref = $bindable(null), value = $bindable(), ...restProps }: DropdownMenuPrimitive.RadioGroupProps = $props();
ref = $bindable(null),
value = $bindable(),
...restProps
}: DropdownMenuPrimitive.RadioGroupProps = $props();
</script> </script>
<DropdownMenuPrimitive.RadioGroup <DropdownMenuPrimitive.RadioGroup bind:ref bind:value data-slot="dropdown-menu-radio-group" {...restProps} />
bind:ref
bind:value
data-slot="dropdown-menu-radio-group"
{...restProps}
/>
@@ -1,33 +1,31 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import CircleIcon from "@lucide/svelte/icons/circle"; import CircleIcon from "@lucide/svelte/icons/circle";
import { cn, type WithoutChild } from "$lib/utils.js"; import { cn, type WithoutChild } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children: childrenProp, children: childrenProp,
...restProps ...restProps
}: WithoutChild<DropdownMenuPrimitive.RadioItemProps> = $props(); }: WithoutChild<DropdownMenuPrimitive.RadioItemProps> = $props();
</script> </script>
<DropdownMenuPrimitive.RadioItem <DropdownMenuPrimitive.RadioItem
bind:ref bind:ref
data-slot="dropdown-menu-radio-item" data-slot="dropdown-menu-radio-item"
class={cn( class={cn(
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 ps-8 pe-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 ps-8 pe-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
{...restProps} {...restProps}
> >
{#snippet children({ checked })} {#snippet children({ checked })}
<span <span class="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center">
class="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center" {#if checked}
> <CircleIcon class="size-2 fill-current" />
{#if checked} {/if}
<CircleIcon class="size-2 fill-current" /> </span>
{/if} {@render childrenProp?.({ checked })}
</span> {/snippet}
{@render childrenProp?.({ checked })}
{/snippet}
</DropdownMenuPrimitive.RadioItem> </DropdownMenuPrimitive.RadioItem>
@@ -1,17 +1,13 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
let { let { ref = $bindable(null), class: className, ...restProps }: DropdownMenuPrimitive.SeparatorProps = $props();
ref = $bindable(null),
class: className,
...restProps
}: DropdownMenuPrimitive.SeparatorProps = $props();
</script> </script>
<DropdownMenuPrimitive.Separator <DropdownMenuPrimitive.Separator
bind:ref bind:ref
data-slot="dropdown-menu-separator" data-slot="dropdown-menu-separator"
class={cn("bg-border -mx-1 my-1 h-px", className)} class={cn("bg-border -mx-1 my-1 h-px", className)}
{...restProps} {...restProps}
/> />
@@ -1,20 +1,20 @@
<script lang="ts"> <script lang="ts">
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();
</script> </script>
<span <span
bind:this={ref} bind:this={ref}
data-slot="dropdown-menu-shortcut" data-slot="dropdown-menu-shortcut"
class={cn("text-muted-foreground ms-auto text-xs tracking-widest", className)} class={cn("text-muted-foreground ms-auto text-xs tracking-widest", className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</span> </span>
@@ -1,20 +1,16 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
let { let { ref = $bindable(null), class: className, ...restProps }: DropdownMenuPrimitive.SubContentProps = $props();
ref = $bindable(null),
class: className,
...restProps
}: DropdownMenuPrimitive.SubContentProps = $props();
</script> </script>
<DropdownMenuPrimitive.SubContent <DropdownMenuPrimitive.SubContent
bind:ref bind:ref
data-slot="dropdown-menu-sub-content" data-slot="dropdown-menu-sub-content"
class={cn( class={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-end-2 data-[side=right]:slide-in-from-start-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--bits-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg", "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-end-2 data-[side=right]:slide-in-from-start-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--bits-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
className className
)} )}
{...restProps} {...restProps}
/> />
@@ -1,29 +1,29 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import ChevronRightIcon from "@lucide/svelte/icons/chevron-right"; import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
inset, inset,
children, children,
...restProps ...restProps
}: DropdownMenuPrimitive.SubTriggerProps & { }: DropdownMenuPrimitive.SubTriggerProps & {
inset?: boolean; inset?: boolean;
} = $props(); } = $props();
</script> </script>
<DropdownMenuPrimitive.SubTrigger <DropdownMenuPrimitive.SubTrigger
bind:ref bind:ref
data-slot="dropdown-menu-sub-trigger" data-slot="dropdown-menu-sub-trigger"
data-inset={inset} data-inset={inset}
class={cn( class={cn(
"data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:ps-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:ps-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
<ChevronRightIcon class="ms-auto size-4" /> <ChevronRightIcon class="ms-auto size-4" />
</DropdownMenuPrimitive.SubTrigger> </DropdownMenuPrimitive.SubTrigger>
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { open = $bindable(false), ...restProps }: DropdownMenuPrimitive.SubProps = $props(); let { open = $bindable(false), ...restProps }: DropdownMenuPrimitive.SubProps = $props();
</script> </script>
<DropdownMenuPrimitive.Sub bind:open {...restProps} /> <DropdownMenuPrimitive.Sub bind:open {...restProps} />
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.TriggerProps = $props(); let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.TriggerProps = $props();
</script> </script>
<DropdownMenuPrimitive.Trigger bind:ref data-slot="dropdown-menu-trigger" {...restProps} /> <DropdownMenuPrimitive.Trigger bind:ref data-slot="dropdown-menu-trigger" {...restProps} />
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui"; import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
let { open = $bindable(false), ...restProps }: DropdownMenuPrimitive.RootProps = $props(); let { open = $bindable(false), ...restProps }: DropdownMenuPrimitive.RootProps = $props();
</script> </script>
<DropdownMenuPrimitive.Root bind:open {...restProps} /> <DropdownMenuPrimitive.Root bind:open {...restProps} />
+34 -34
View File
@@ -17,38 +17,38 @@ import GroupHeading from "./dropdown-menu-group-heading.svelte";
import Portal from "./dropdown-menu-portal.svelte"; import Portal from "./dropdown-menu-portal.svelte";
export { export {
CheckboxGroup, CheckboxGroup,
CheckboxItem, CheckboxItem,
Content, Content,
Portal, Portal,
Root as DropdownMenu, Root as DropdownMenu,
CheckboxGroup as DropdownMenuCheckboxGroup, CheckboxGroup as DropdownMenuCheckboxGroup,
CheckboxItem as DropdownMenuCheckboxItem, CheckboxItem as DropdownMenuCheckboxItem,
Content as DropdownMenuContent, Content as DropdownMenuContent,
Portal as DropdownMenuPortal, Portal as DropdownMenuPortal,
Group as DropdownMenuGroup, Group as DropdownMenuGroup,
Item as DropdownMenuItem, Item as DropdownMenuItem,
Label as DropdownMenuLabel, Label as DropdownMenuLabel,
RadioGroup as DropdownMenuRadioGroup, RadioGroup as DropdownMenuRadioGroup,
RadioItem as DropdownMenuRadioItem, RadioItem as DropdownMenuRadioItem,
Separator as DropdownMenuSeparator, Separator as DropdownMenuSeparator,
Shortcut as DropdownMenuShortcut, Shortcut as DropdownMenuShortcut,
Sub as DropdownMenuSub, Sub as DropdownMenuSub,
SubContent as DropdownMenuSubContent, SubContent as DropdownMenuSubContent,
SubTrigger as DropdownMenuSubTrigger, SubTrigger as DropdownMenuSubTrigger,
Trigger as DropdownMenuTrigger, Trigger as DropdownMenuTrigger,
GroupHeading as DropdownMenuGroupHeading, GroupHeading as DropdownMenuGroupHeading,
Group, Group,
GroupHeading, GroupHeading,
Item, Item,
Label, Label,
RadioGroup, RadioGroup,
RadioItem, RadioItem,
Root, Root,
Separator, Separator,
Shortcut, Shortcut,
Sub, Sub,
SubContent, SubContent,
SubTrigger, SubTrigger,
Trigger, Trigger,
}; };
@@ -1,20 +1,20 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="field-content" data-slot="field-content"
class={cn("group/field-content flex flex-1 flex-col gap-1.5 leading-snug", className)} class={cn("group/field-content flex flex-1 flex-col gap-1.5 leading-snug", className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
@@ -1,25 +1,25 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLParagraphElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLParagraphElement>> = $props();
</script> </script>
<p <p
bind:this={ref} bind:this={ref}
data-slot="field-description" data-slot="field-description"
class={cn( class={cn(
"text-muted-foreground text-sm leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance", "text-muted-foreground text-sm leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance",
"last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5", "last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5",
"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4", "[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
className className
)} )}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</p> </p>
+47 -47
View File
@@ -1,58 +1,58 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
errors, errors,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & { }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
children?: Snippet; children?: Snippet;
errors?: { message?: string }[]; errors?: { message?: string }[];
} = $props(); } = $props();
const hasContent = $derived.by(() => { const hasContent = $derived.by(() => {
// has slotted error // has slotted error
if (children) return true; if (children) return true;
// no errors // no errors
if (!errors) return false; if (!errors) return false;
// has an error but no message // has an error but no message
if (errors.length === 1 && !errors[0]?.message) { if (errors.length === 1 && !errors[0]?.message) {
return false; return false;
} }
return true; return true;
}); });
const isMultipleErrors = $derived(errors && errors.length > 1); const isMultipleErrors = $derived(errors && errors.length > 1);
const singleErrorMessage = $derived(errors && errors.length === 1 && errors[0]?.message); const singleErrorMessage = $derived(errors && errors.length === 1 && errors[0]?.message);
</script> </script>
{#if hasContent} {#if hasContent}
<div <div
bind:this={ref} bind:this={ref}
role="alert" role="alert"
data-slot="field-error" data-slot="field-error"
class={cn("text-destructive text-sm font-normal", className)} class={cn("text-destructive text-sm font-normal", className)}
{...restProps} {...restProps}
> >
{#if children} {#if children}
{@render children()} {@render children()}
{:else if singleErrorMessage} {:else if singleErrorMessage}
{singleErrorMessage} {singleErrorMessage}
{:else if isMultipleErrors} {:else if isMultipleErrors}
<ul class="ms-4 flex list-disc flex-col gap-1"> <ul class="ms-4 flex list-disc flex-col gap-1">
{#each errors ?? [] as error, index (index)} {#each errors ?? [] as error, index (index)}
{#if error?.message} {#if error?.message}
<li>{error.message}</li> <li>{error.message}</li>
{/if} {/if}
{/each} {/each}
</ul> </ul>
{/if} {/if}
</div> </div>
{/if} {/if}
+16 -16
View File
@@ -1,23 +1,23 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="field-group" data-slot="field-group"
class={cn( class={cn(
"group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4", "group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4",
className className
)} )}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
+14 -19
View File
@@ -1,26 +1,21 @@
<script lang="ts"> <script lang="ts">
import { Label } from "$lib/components/ui/label/index.js"; import { Label } from "$lib/components/ui/label/index.js";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
import type { ComponentProps } from "svelte"; import type { ComponentProps } from "svelte";
let { let { ref = $bindable(null), class: className, children, ...restProps }: ComponentProps<typeof Label> = $props();
ref = $bindable(null),
class: className,
children,
...restProps
}: ComponentProps<typeof Label> = $props();
</script> </script>
<Label <Label
bind:ref bind:ref
data-slot="field-label" data-slot="field-label"
class={cn( class={cn(
"group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50", "group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50",
"has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>*]:data-[slot=field]:p-4", "has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>*]:data-[slot=field]:p-4",
"has-data-[state=checked]:bg-primary/5 has-data-[state=checked]:border-primary dark:has-data-[state=checked]:bg-primary/10", "has-data-[state=checked]:bg-primary/5 has-data-[state=checked]:border-primary dark:has-data-[state=checked]:bg-primary/10",
className className
)} )}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</Label> </Label>
+17 -22
View File
@@ -1,29 +1,24 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
variant = "legend", variant = "legend",
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLLegendElement>> & { }: WithElementRef<HTMLAttributes<HTMLLegendElement>> & {
variant?: "legend" | "label"; variant?: "legend" | "label";
} = $props(); } = $props();
</script> </script>
<legend <legend
bind:this={ref} bind:this={ref}
data-slot="field-legend" data-slot="field-legend"
data-variant={variant} data-variant={variant}
class={cn( class={cn("mb-3 font-medium", "data-[variant=legend]:text-base", "data-[variant=label]:text-sm", className)}
"mb-3 font-medium", {...restProps}
"data-[variant=legend]:text-base",
"data-[variant=label]:text-sm",
className
)}
{...restProps}
> >
{@render children?.()} {@render children?.()}
</legend> </legend>
@@ -1,38 +1,35 @@
<script lang="ts"> <script lang="ts">
import { Separator } from "$lib/components/ui/separator/index.js"; import { Separator } from "$lib/components/ui/separator/index.js";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & { }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
children?: Snippet; children?: Snippet;
} = $props(); } = $props();
const hasContent = $derived(!!children); const hasContent = $derived(!!children);
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="field-separator" data-slot="field-separator"
data-content={hasContent} data-content={hasContent}
class={cn( class={cn("relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2", className)}
"relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2", {...restProps}
className
)}
{...restProps}
> >
<Separator class="absolute inset-0 top-1/2" /> <Separator class="absolute inset-0 top-1/2" />
{#if children} {#if children}
<span <span
class="bg-background text-muted-foreground relative mx-auto block w-fit px-2" class="bg-background text-muted-foreground relative mx-auto block w-fit px-2"
data-slot="field-separator-content" data-slot="field-separator-content"
> >
{@render children()} {@render children()}
</span> </span>
{/if} {/if}
</div> </div>
+17 -17
View File
@@ -1,24 +1,24 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLFieldsetAttributes } from "svelte/elements"; import type { HTMLFieldsetAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLFieldsetAttributes> = $props(); }: WithElementRef<HTMLFieldsetAttributes> = $props();
</script> </script>
<fieldset <fieldset
bind:this={ref} bind:this={ref}
data-slot="field-set" data-slot="field-set"
class={cn( class={cn(
"flex flex-col gap-6", "flex flex-col gap-6",
"has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3", "has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3",
className className
)} )}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</fieldset> </fieldset>
+16 -16
View File
@@ -1,23 +1,23 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="field-title" data-slot="field-title"
class={cn( class={cn(
"flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50", "flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50",
className className
)} )}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
+41 -41
View File
@@ -1,53 +1,53 @@
<script lang="ts" module> <script lang="ts" module>
import { tv, type VariantProps } from "tailwind-variants"; import { tv, type VariantProps } from "tailwind-variants";
export const fieldVariants = tv({ export const fieldVariants = tv({
base: "group/field data-[invalid=true]:text-destructive flex w-full gap-3", base: "group/field data-[invalid=true]:text-destructive flex w-full gap-3",
variants: { variants: {
orientation: { orientation: {
vertical: "flex-col [&>*]:w-full [&>.sr-only]:w-auto", vertical: "flex-col [&>*]:w-full [&>.sr-only]:w-auto",
horizontal: [ horizontal: [
"flex-row items-center", "flex-row items-center",
"[&>[data-slot=field-label]]:flex-auto", "[&>[data-slot=field-label]]:flex-auto",
"has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", "has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px"
], ],
responsive: [ responsive: [
"flex-col @md/field-group:flex-row @md/field-group:items-center [&>*]:w-full @md/field-group:[&>*]:w-auto [&>.sr-only]:w-auto", "flex-col @md/field-group:flex-row @md/field-group:items-center [&>*]:w-full @md/field-group:[&>*]:w-auto [&>.sr-only]:w-auto",
"@md/field-group:[&>[data-slot=field-label]]:flex-auto", "@md/field-group:[&>[data-slot=field-label]]:flex-auto",
"@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", "@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px"
], ]
}, }
}, },
defaultVariants: { defaultVariants: {
orientation: "vertical", orientation: "vertical"
}, }
}); });
export type FieldOrientation = VariantProps<typeof fieldVariants>["orientation"]; export type FieldOrientation = VariantProps<typeof fieldVariants>["orientation"];
</script> </script>
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
orientation = "vertical", orientation = "vertical",
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & { }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
orientation?: FieldOrientation; orientation?: FieldOrientation;
} = $props(); } = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
role="group" role="group"
data-slot="field" data-slot="field"
data-orientation={orientation} data-orientation={orientation}
class={cn(fieldVariants({ orientation }), className)} class={cn(fieldVariants({ orientation }), className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
+20 -20
View File
@@ -10,24 +10,24 @@ import Separator from "./field-separator.svelte";
import Error from "./field-error.svelte"; import Error from "./field-error.svelte";
export { export {
Field, Field,
Set, Set,
Legend, Legend,
Group, Group,
Content, Content,
Label, Label,
Title, Title,
Description, Description,
Separator, Separator,
Error, Error,
// //
Set as FieldSet, Set as FieldSet,
Legend as FieldLegend, Legend as FieldLegend,
Group as FieldGroup, Group as FieldGroup,
Content as FieldContent, Content as FieldContent,
Label as FieldLabel, Label as FieldLabel,
Title as FieldTitle, Title as FieldTitle,
Description as FieldDescription, Description as FieldDescription,
Separator as FieldSeparator, Separator as FieldSeparator,
Error as FieldError, Error as FieldError,
}; };
+13 -13
View File
@@ -6,17 +6,17 @@ import Text from "./input-group-text.svelte";
import Textarea from "./input-group-textarea.svelte"; import Textarea from "./input-group-textarea.svelte";
export { export {
Root, Root,
Addon, Addon,
Button, Button,
Input, Input,
Text, Text,
Textarea, Textarea,
// //
Root as InputGroup, Root as InputGroup,
Addon as InputGroupAddon, Addon as InputGroupAddon,
Button as InputGroupButton, Button as InputGroupButton,
Input as InputGroupInput, Input as InputGroupInput,
Text as InputGroupText, Text as InputGroupText,
Textarea as InputGroupTextarea, Textarea as InputGroupTextarea,
}; };
@@ -1,55 +1,52 @@
<script lang="ts" module> <script lang="ts" module>
import { tv, type VariantProps } from "tailwind-variants"; import { tv, type VariantProps } from "tailwind-variants";
export const inputGroupAddonVariants = tv({ export const inputGroupAddonVariants = tv({
base: "text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4", base: "text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
variants: { variants: {
align: { align: {
"inline-start": "inline-start": "order-first ps-3 has-[>button]:ms-[-0.45rem] has-[>kbd]:ms-[-0.35rem]",
"order-first ps-3 has-[>button]:ms-[-0.45rem] has-[>kbd]:ms-[-0.35rem]", "inline-end": "order-last pe-3 has-[>button]:me-[-0.45rem] has-[>kbd]:me-[-0.35rem]",
"inline-end": "block-start":
"order-last pe-3 has-[>button]:me-[-0.45rem] has-[>kbd]:me-[-0.35rem]", "order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5 [.border-b]:pb-3",
"block-start": "block-end": "order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5 [.border-t]:pt-3"
"order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5 [.border-b]:pb-3", }
"block-end": },
"order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5 [.border-t]:pt-3", defaultVariants: {
}, align: "inline-start"
}, }
defaultVariants: { });
align: "inline-start",
},
});
export type InputGroupAddonAlign = VariantProps<typeof inputGroupAddonVariants>["align"]; export type InputGroupAddonAlign = VariantProps<typeof inputGroupAddonVariants>["align"];
</script> </script>
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
align = "inline-start", align = "inline-start",
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & { }: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
align?: InputGroupAddonAlign; align?: InputGroupAddonAlign;
} = $props(); } = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
role="group" role="group"
data-slot="input-group-addon" data-slot="input-group-addon"
data-align={align} data-align={align}
class={cn(inputGroupAddonVariants({ align }), className)} class={cn(inputGroupAddonVariants({ align }), className)}
onclick={(e) => { onclick={(e) => {
if ((e.target as HTMLElement).closest("button")) { if ((e.target as HTMLElement).closest("button")) {
return; return;
} }
e.currentTarget.parentElement?.querySelector("input")?.focus(); e.currentTarget.parentElement?.querySelector("input")?.focus();
}} }}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</div> </div>
@@ -1,49 +1,49 @@
<script lang="ts" module> <script lang="ts" module>
import { tv, type VariantProps } from "tailwind-variants"; import { tv, type VariantProps } from "tailwind-variants";
const inputGroupButtonVariants = tv({ const inputGroupButtonVariants = tv({
base: "flex items-center gap-2 text-sm shadow-none", base: "flex items-center gap-2 text-sm shadow-none",
variants: { variants: {
size: { size: {
xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5", xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5", sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5",
"icon-xs": "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0", "icon-xs": "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
"icon-sm": "size-8 p-0 has-[>svg]:p-0", "icon-sm": "size-8 p-0 has-[>svg]:p-0"
}, }
}, },
defaultVariants: { defaultVariants: {
size: "xs", size: "xs"
}, }
}); });
export type InputGroupButtonSize = VariantProps<typeof inputGroupButtonVariants>["size"]; export type InputGroupButtonSize = VariantProps<typeof inputGroupButtonVariants>["size"];
</script> </script>
<script lang="ts"> <script lang="ts">
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
import type { ComponentProps } from "svelte"; import type { ComponentProps } from "svelte";
import { Button } from "$lib/components/ui/button/index.js"; import { Button } from "$lib/components/ui/button/index.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
type = "button", type = "button",
variant = "ghost", variant = "ghost",
size = "xs", size = "xs",
...restProps ...restProps
}: Omit<ComponentProps<typeof Button>, "href" | "size"> & { }: Omit<ComponentProps<typeof Button>, "href" | "size"> & {
size?: InputGroupButtonSize; size?: InputGroupButtonSize;
} = $props(); } = $props();
</script> </script>
<Button <Button
bind:ref bind:ref
{type} {type}
data-size={size} data-size={size}
{variant} {variant}
class={cn(inputGroupButtonVariants({ size }), className)} class={cn(inputGroupButtonVariants({ size }), className)}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</Button> </Button>
@@ -1,23 +1,23 @@
<script lang="ts"> <script lang="ts">
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
import type { ComponentProps } from "svelte"; import type { ComponentProps } from "svelte";
import { Input } from "$lib/components/ui/input/index.js"; import { Input } from "$lib/components/ui/input/index.js";
let { let {
ref = $bindable(null), ref = $bindable(null),
value = $bindable(), value = $bindable(),
class: className, class: className,
...props ...props
}: ComponentProps<typeof Input> = $props(); }: ComponentProps<typeof Input> = $props();
</script> </script>
<Input <Input
bind:ref bind:ref
data-slot="input-group-control" data-slot="input-group-control"
class={cn( class={cn(
"flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent", "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",
className className
)} )}
bind:value bind:value
{...props} {...props}
/> />
@@ -1,22 +1,22 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...restProps ...restProps
}: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();
</script> </script>
<span <span
bind:this={ref} bind:this={ref}
class={cn( class={cn(
"text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4", "text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
className className
)} )}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}
</span> </span>
@@ -1,23 +1,23 @@
<script lang="ts"> <script lang="ts">
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
import { Textarea } from "$lib/components/ui/textarea/index.js"; import { Textarea } from "$lib/components/ui/textarea/index.js";
import type { ComponentProps } from "svelte"; import type { ComponentProps } from "svelte";
let { let {
ref = $bindable(null), ref = $bindable(null),
value = $bindable(), value = $bindable(),
class: className, class: className,
...props ...props
}: ComponentProps<typeof Textarea> = $props(); }: ComponentProps<typeof Textarea> = $props();
</script> </script>
<Textarea <Textarea
bind:ref bind:ref
data-slot="input-group-control" data-slot="input-group-control"
class={cn( class={cn(
"flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent", "flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",
className className
)} )}
bind:value bind:value
{...props} {...props}
/> />
@@ -1,38 +1,38 @@
<script lang="ts"> <script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements"; import type { HTMLAttributes } from "svelte/elements";
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children, children,
...props ...props
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props(); }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
</script> </script>
<div <div
bind:this={ref} bind:this={ref}
data-slot="input-group" data-slot="input-group"
role="group" role="group"
class={cn( class={cn(
"group/input-group border-input dark:bg-input/30 relative flex w-full items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none", "group/input-group border-input dark:bg-input/30 relative flex w-full items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none",
"h-9 has-[>textarea]:h-auto", "h-9 has-[>textarea]:h-auto",
// Variants based on alignment. // Variants based on alignment.
"has-[>[data-align=inline-start]]:[&>input]:ps-2", "has-[>[data-align=inline-start]]:[&>input]:ps-2",
"has-[>[data-align=inline-end]]:[&>input]:pe-2", "has-[>[data-align=inline-end]]:[&>input]:pe-2",
"has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3", "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
"has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3", "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
// Focus state. // Focus state.
"has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]", "has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]",
// Error state. // Error state.
"has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40", "has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",
className className
)} )}
{...props} {...props}
> >
{@render children?.()} {@render children?.()}
</div> </div>
+3 -3
View File
@@ -1,7 +1,7 @@
import Root from "./input.svelte"; import Root from "./input.svelte";
export { export {
Root, Root,
// //
Root as Input, Root as Input,
}; };
+42 -43
View File
@@ -1,52 +1,51 @@
<script lang="ts"> <script lang="ts">
import type { HTMLInputAttributes, HTMLInputTypeAttribute } from "svelte/elements"; import type { HTMLInputAttributes, HTMLInputTypeAttribute } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js"; import { cn, type WithElementRef } from "$lib/utils.js";
type InputType = Exclude<HTMLInputTypeAttribute, "file">; type InputType = Exclude<HTMLInputTypeAttribute, "file">;
type Props = WithElementRef< type Props = WithElementRef<
Omit<HTMLInputAttributes, "type"> & Omit<HTMLInputAttributes, "type"> & ({ type: "file"; files?: FileList } | { type?: InputType; files?: undefined })
({ type: "file"; files?: FileList } | { type?: InputType; files?: undefined }) >;
>;
let { let {
ref = $bindable(null), ref = $bindable(null),
value = $bindable(), value = $bindable(),
type, type,
files = $bindable(), files = $bindable(),
class: className, class: className,
"data-slot": dataSlot = "input", "data-slot": dataSlot = "input",
...restProps ...restProps
}: Props = $props(); }: Props = $props();
</script> </script>
{#if type === "file"} {#if type === "file"}
<input <input
bind:this={ref} bind:this={ref}
data-slot={dataSlot} data-slot={dataSlot}
class={cn( class={cn(
"selection:bg-primary dark:bg-input/30 selection:text-primary-foreground border-input ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 pt-1.5 text-sm font-medium shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50", "selection:bg-primary dark:bg-input/30 selection:text-primary-foreground border-input ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 pt-1.5 text-sm font-medium shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
className className
)} )}
type="file" type="file"
bind:files bind:files
bind:value bind:value
{...restProps} {...restProps}
/> />
{:else} {:else}
<input <input
bind:this={ref} bind:this={ref}
data-slot={dataSlot} data-slot={dataSlot}
class={cn( class={cn(
"border-input bg-background selection:bg-primary dark:bg-input/30 selection:text-primary-foreground ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "border-input bg-background selection:bg-primary dark:bg-input/30 selection:text-primary-foreground ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
className className
)} )}
{type} {type}
bind:value bind:value
{...restProps} {...restProps}
/> />
{/if} {/if}

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