mirror of
https://github.com/rajnandan1/kener.git
synced 2026-06-23 04:10:22 +00:00
changes
This commit is contained in:
@@ -29,3 +29,4 @@ static/uploads/*
|
||||
!static/uploads/upload.dir
|
||||
temp.txt
|
||||
temp.js
|
||||
.DS_Store
|
||||
|
||||
@@ -24,9 +24,7 @@ export function up(knex) {
|
||||
table.timestamp("updated_at").defaultTo(knex.fn.now());
|
||||
})
|
||||
// Add index to monitor_alerts table
|
||||
.raw(
|
||||
"CREATE INDEX idx_monitor_tag_created_at ON monitor_alerts (monitor_tag, created_at)"
|
||||
)
|
||||
.raw("CREATE INDEX idx_monitor_tag_created_at ON monitor_alerts (monitor_tag, created_at)")
|
||||
.createTable("site_data", (table) => {
|
||||
table.increments("id").primary();
|
||||
table.string("key", 255).notNullable().unique();
|
||||
|
||||
Generated
+2
-359
@@ -128,8 +128,8 @@
|
||||
}
|
||||
},
|
||||
"../aven": {
|
||||
"name": "@rajnandan1/aven",
|
||||
"version": "0.1.1",
|
||||
"name": "@rajnandan1/atticus",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@openai/agents": "^0.3.7",
|
||||
@@ -3008,17 +3008,6 @@
|
||||
"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": {
|
||||
"version": "3.0.3",
|
||||
"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": {
|
||||
"version": "0.3.9",
|
||||
"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": {
|
||||
"version": "0.3.9",
|
||||
"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": {
|
||||
"version": "1.0.0-next.29",
|
||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
|
||||
@@ -8291,268 +8211,6 @@
|
||||
"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": {
|
||||
"version": "3.1.3",
|
||||
"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": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte-codemirror-editor/-/svelte-codemirror-editor-2.1.0.tgz",
|
||||
|
||||
@@ -21,6 +21,8 @@ export async function seed(knex: Knex): Promise<void> {
|
||||
day_degraded_minimum_count: monitor.day_degraded_minimum_count,
|
||||
day_down_minimum_count: monitor.day_down_minimum_count,
|
||||
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(),
|
||||
updated_at: knex.fn.now(),
|
||||
});
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
{/if}
|
||||
|
||||
<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">
|
||||
{#if data.site.logo}
|
||||
<GMI src={data.site.logo} classList="w-8" alt={data.site.title} srcset="" />
|
||||
@@ -82,7 +82,7 @@
|
||||
<a
|
||||
rel="external"
|
||||
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={() =>
|
||||
analyticsEvent("navigation", {
|
||||
name: navItem.name
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
<h2 class="mb-1 text-sm font-semibold">
|
||||
{l(lang, "Share")}
|
||||
</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")}
|
||||
</p>
|
||||
<Button class="h-8 px-2 pr-4 text-xs font-semibold" variant="secondary" on:click={copyLinkToClipboard}>
|
||||
@@ -160,7 +160,7 @@
|
||||
href={pathMonitorLink}
|
||||
target="_blank"
|
||||
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} />
|
||||
</Button>
|
||||
@@ -170,7 +170,7 @@
|
||||
<h2 class="mb-1 text-sm font-semibold">
|
||||
{l(lang, "Embed")}
|
||||
</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 <script> or <iframe> in your app.")}
|
||||
</p>
|
||||
<div class="mb-4 grid grid-cols-2 gap-2">
|
||||
@@ -226,7 +226,7 @@
|
||||
<h2 class="mb-1 text-sm font-semibold">
|
||||
{l(lang, "Badge")}
|
||||
</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")}
|
||||
</p>
|
||||
<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">
|
||||
{l(lang, "LIVE Status")}
|
||||
</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")}
|
||||
</p>
|
||||
<Button class="h-8 px-2 pr-4 text-xs" variant="secondary" on:click={copyDotStandard}>
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Accordion as AccordionPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: AccordionPrimitive.ItemProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: AccordionPrimitive.ItemProps = $props();
|
||||
</script>
|
||||
|
||||
<AccordionPrimitive.Item
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Accordion as AccordionPrimitive } from "bits-ui";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
value = $bindable(),
|
||||
...restProps
|
||||
}: AccordionPrimitive.RootProps = $props();
|
||||
let { ref = $bindable(null), value = $bindable(), ...restProps }: AccordionPrimitive.RootProps = $props();
|
||||
</script>
|
||||
|
||||
<AccordionPrimitive.Root
|
||||
bind:ref
|
||||
bind:value={value as never}
|
||||
data-slot="accordion"
|
||||
{...restProps}
|
||||
/>
|
||||
<AccordionPrimitive.Root bind:ref bind:value={value as never} data-slot="accordion" {...restProps} />
|
||||
|
||||
@@ -6,13 +6,12 @@
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-card text-card-foreground",
|
||||
destructive:
|
||||
"text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-current",
|
||||
},
|
||||
destructive: "text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-current"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
variant: "default"
|
||||
}
|
||||
});
|
||||
|
||||
export type AlertVariant = VariantProps<typeof alertVariants>["variant"];
|
||||
@@ -33,12 +32,6 @@
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={ref}
|
||||
data-slot="alert"
|
||||
class={cn(alertVariants({ variant }), className)}
|
||||
{...restProps}
|
||||
role="alert"
|
||||
>
|
||||
<div bind:this={ref} data-slot="alert" class={cn(alertVariants({ variant }), className)} {...restProps} role="alert">
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: AvatarPrimitive.FallbackProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: AvatarPrimitive.FallbackProps = $props();
|
||||
</script>
|
||||
|
||||
<AvatarPrimitive.Fallback
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: AvatarPrimitive.ImageProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: AvatarPrimitive.ImageProps = $props();
|
||||
</script>
|
||||
|
||||
<AvatarPrimitive.Image
|
||||
|
||||
@@ -5,18 +5,16 @@
|
||||
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: {
|
||||
variant: {
|
||||
default:
|
||||
"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",
|
||||
default: "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",
|
||||
destructive:
|
||||
"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",
|
||||
},
|
||||
outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
variant: "default"
|
||||
}
|
||||
});
|
||||
|
||||
export type BadgeVariant = VariantProps<typeof badgeVariants>["variant"];
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
import type { HTMLLiAttributes } from "svelte/elements";
|
||||
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLLiAttributes> = $props();
|
||||
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLLiAttributes> = $props();
|
||||
</script>
|
||||
|
||||
<li
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"data-slot": "breadcrumb-link",
|
||||
class: cn("hover:text-foreground transition-colors", className),
|
||||
href,
|
||||
...restProps,
|
||||
...restProps
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,21 +2,13 @@
|
||||
import type { HTMLOlAttributes } from "svelte/elements";
|
||||
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLOlAttributes> = $props();
|
||||
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLOlAttributes> = $props();
|
||||
</script>
|
||||
|
||||
<ol
|
||||
bind:this={ref}
|
||||
data-slot="breadcrumb-list"
|
||||
class={cn(
|
||||
"text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
|
||||
className
|
||||
)}
|
||||
class={cn("text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5", className)}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
|
||||
@@ -3,12 +3,7 @@
|
||||
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||
import type { HTMLLiAttributes } from "svelte/elements";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLLiAttributes> = $props();
|
||||
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLLiAttributes> = $props();
|
||||
</script>
|
||||
|
||||
<li
|
||||
|
||||
@@ -10,12 +10,6 @@
|
||||
}: WithElementRef<HTMLAttributes<HTMLElement>> = $props();
|
||||
</script>
|
||||
|
||||
<nav
|
||||
bind:this={ref}
|
||||
data-slot="breadcrumb"
|
||||
class={className}
|
||||
aria-label="breadcrumb"
|
||||
{...restProps}
|
||||
>
|
||||
<nav bind:this={ref} data-slot="breadcrumb" class={className} aria-label="breadcrumb" {...restProps}>
|
||||
{@render children?.()}
|
||||
</nav>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
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",
|
||||
className
|
||||
),
|
||||
)
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
horizontal:
|
||||
"[&>*:not(:first-child)]:rounded-s-none [&>*:not(:first-child)]:border-s-0 [&>*:not(:last-child)]:rounded-e-none",
|
||||
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: {
|
||||
orientation: "horizontal",
|
||||
},
|
||||
orientation: "horizontal"
|
||||
}
|
||||
});
|
||||
|
||||
export type ButtonGroupOrientation = VariantProps<typeof buttonGroupVariants>["orientation"];
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"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",
|
||||
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: {
|
||||
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
||||
@@ -22,13 +22,13 @@
|
||||
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
||||
icon: "size-9",
|
||||
"icon-sm": "size-8",
|
||||
"icon-lg": "size-10",
|
||||
},
|
||||
"icon-lg": "size-10"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
size: "default"
|
||||
}
|
||||
});
|
||||
|
||||
export type ButtonVariant = VariantProps<typeof buttonVariants>["variant"];
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import Root, {
|
||||
type ButtonProps,
|
||||
type ButtonSize,
|
||||
type ButtonVariant,
|
||||
buttonVariants,
|
||||
} from "./button.svelte";
|
||||
import Root, { type ButtonProps, type ButtonSize, type ButtonVariant, buttonVariants } from "./button.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
|
||||
@@ -10,11 +10,6 @@
|
||||
}: WithElementRef<HTMLAttributes<HTMLParagraphElement>> = $props();
|
||||
</script>
|
||||
|
||||
<p
|
||||
bind:this={ref}
|
||||
data-slot="card-description"
|
||||
class={cn("text-muted-foreground text-sm", className)}
|
||||
{...restProps}
|
||||
>
|
||||
<p bind:this={ref} data-slot="card-description" class={cn("text-muted-foreground text-sm", className)} {...restProps}>
|
||||
{@render children?.()}
|
||||
</p>
|
||||
|
||||
@@ -10,11 +10,6 @@
|
||||
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={ref}
|
||||
data-slot="card-title"
|
||||
class={cn("leading-none font-semibold", className)}
|
||||
{...restProps}
|
||||
>
|
||||
<div bind:this={ref} data-slot="card-title" class={cn("leading-none font-semibold", className)} {...restProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
@@ -13,10 +13,7 @@
|
||||
<div
|
||||
bind:this={ref}
|
||||
data-slot="card"
|
||||
class={cn(
|
||||
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
||||
className
|
||||
)}
|
||||
class={cn("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", className)}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
setChartContext({
|
||||
get config() {
|
||||
return config;
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
item: TooltipPayload;
|
||||
index: number;
|
||||
payload: TooltipPayload[];
|
||||
},
|
||||
}
|
||||
]
|
||||
>;
|
||||
} = $props();
|
||||
@@ -111,7 +111,7 @@
|
||||
name: item.name,
|
||||
item,
|
||||
index: i,
|
||||
payload: tooltipCtx.payload,
|
||||
payload: tooltipCtx.payload
|
||||
})}
|
||||
{:else}
|
||||
{#if itemConfig?.icon}
|
||||
@@ -119,23 +119,16 @@
|
||||
{:else if !hideIndicator}
|
||||
<div
|
||||
style="--color-bg: {indicatorColor}; --color-border: {indicatorColor};"
|
||||
class={cn(
|
||||
"shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
|
||||
{
|
||||
class={cn("shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)", {
|
||||
"size-2.5": indicator === "dot",
|
||||
"h-full w-1": indicator === "line",
|
||||
"w-0 border-[1.5px] border-dashed bg-transparent":
|
||||
indicator === "dashed",
|
||||
"my-0.5": nestLabel && indicator === "dashed",
|
||||
}
|
||||
)}
|
||||
"w-0 border-[1.5px] border-dashed bg-transparent": indicator === "dashed",
|
||||
"my-0.5": nestLabel && indicator === "dashed"
|
||||
})}
|
||||
></div>
|
||||
{/if}
|
||||
<div
|
||||
class={cn(
|
||||
"flex flex-1 shrink-0 justify-between leading-none",
|
||||
nestLabel ? "items-end" : "items-center"
|
||||
)}
|
||||
class={cn("flex flex-1 shrink-0 justify-between leading-none", nestLabel ? "items-end" : "items-center")}
|
||||
>
|
||||
<div class="grid gap-1.5">
|
||||
{#if nestLabel}
|
||||
|
||||
@@ -7,24 +7,15 @@ export type ChartConfig = {
|
||||
[k in string]: {
|
||||
label?: string;
|
||||
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 TooltipPayload = ExtractSnippetParams<
|
||||
ComponentProps<typeof Tooltip.Root>["children"]
|
||||
>["payload"][number];
|
||||
export type TooltipPayload = ExtractSnippetParams<ComponentProps<typeof Tooltip.Root>["children"]>["payload"][number];
|
||||
|
||||
// Helper to extract item config from a payload.
|
||||
export function getPayloadConfigFromPayload(
|
||||
config: ChartConfig,
|
||||
payload: TooltipPayload,
|
||||
key: string
|
||||
) {
|
||||
export function getPayloadConfigFromPayload(config: ChartConfig, payload: TooltipPayload, key: string) {
|
||||
if (typeof payload !== "object" || payload === null) return undefined;
|
||||
|
||||
const payloadPayload =
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DialogPrimitive.DescriptionProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: DialogPrimitive.DescriptionProps = $props();
|
||||
</script>
|
||||
|
||||
<DialogPrimitive.Description
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DialogPrimitive.OverlayProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: DialogPrimitive.OverlayProps = $props();
|
||||
</script>
|
||||
|
||||
<DialogPrimitive.Overlay
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DialogPrimitive.TitleProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: DialogPrimitive.TitleProps = $props();
|
||||
</script>
|
||||
|
||||
<DialogPrimitive.Title
|
||||
|
||||
@@ -8,9 +8,4 @@
|
||||
}: DropdownMenuPrimitive.CheckboxGroupProps = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.CheckboxGroup
|
||||
bind:ref
|
||||
bind:value
|
||||
data-slot="dropdown-menu-checkbox-group"
|
||||
{...restProps}
|
||||
/>
|
||||
<DropdownMenuPrimitive.CheckboxGroup bind:ref bind:value data-slot="dropdown-menu-checkbox-group" {...restProps} />
|
||||
|
||||
@@ -29,9 +29,7 @@
|
||||
{...restProps}
|
||||
>
|
||||
{#snippet children({ checked, indeterminate })}
|
||||
<span
|
||||
class="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center"
|
||||
>
|
||||
<span class="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center">
|
||||
{#if indeterminate}
|
||||
<MinusIcon class="size-4" />
|
||||
{:else}
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
value = $bindable(),
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.RadioGroupProps = $props();
|
||||
let { ref = $bindable(null), value = $bindable(), ...restProps }: DropdownMenuPrimitive.RadioGroupProps = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.RadioGroup
|
||||
bind:ref
|
||||
bind:value
|
||||
data-slot="dropdown-menu-radio-group"
|
||||
{...restProps}
|
||||
/>
|
||||
<DropdownMenuPrimitive.RadioGroup bind:ref bind:value data-slot="dropdown-menu-radio-group" {...restProps} />
|
||||
|
||||
@@ -21,9 +21,7 @@
|
||||
{...restProps}
|
||||
>
|
||||
{#snippet children({ checked })}
|
||||
<span
|
||||
class="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center"
|
||||
>
|
||||
<span class="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center">
|
||||
{#if checked}
|
||||
<CircleIcon class="size-2 fill-current" />
|
||||
{/if}
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.SeparatorProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: DropdownMenuPrimitive.SeparatorProps = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.Separator
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DropdownMenuPrimitive.SubContentProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: DropdownMenuPrimitive.SubContentProps = $props();
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
|
||||
@@ -3,12 +3,7 @@
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { ComponentProps } from "svelte";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: ComponentProps<typeof Label> = $props();
|
||||
let { ref = $bindable(null), class: className, children, ...restProps }: ComponentProps<typeof Label> = $props();
|
||||
</script>
|
||||
|
||||
<Label
|
||||
|
||||
@@ -17,12 +17,7 @@
|
||||
bind:this={ref}
|
||||
data-slot="field-legend"
|
||||
data-variant={variant}
|
||||
class={cn(
|
||||
"mb-3 font-medium",
|
||||
"data-[variant=legend]:text-base",
|
||||
"data-[variant=label]:text-sm",
|
||||
className
|
||||
)}
|
||||
class={cn("mb-3 font-medium", "data-[variant=legend]:text-base", "data-[variant=label]:text-sm", className)}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
|
||||
@@ -20,10 +20,7 @@
|
||||
bind:this={ref}
|
||||
data-slot="field-separator"
|
||||
data-content={hasContent}
|
||||
class={cn(
|
||||
"relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2",
|
||||
className
|
||||
)}
|
||||
class={cn("relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2", className)}
|
||||
{...restProps}
|
||||
>
|
||||
<Separator class="absolute inset-0 top-1/2" />
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
horizontal: [
|
||||
"flex-row items-center",
|
||||
"[&>[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: [
|
||||
"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: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: {
|
||||
orientation: "vertical",
|
||||
},
|
||||
orientation: "vertical"
|
||||
}
|
||||
});
|
||||
|
||||
export type FieldOrientation = VariantProps<typeof fieldVariants>["orientation"];
|
||||
|
||||
@@ -4,19 +4,16 @@
|
||||
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: {
|
||||
align: {
|
||||
"inline-start":
|
||||
"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-start": "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]",
|
||||
"block-start":
|
||||
"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",
|
||||
},
|
||||
"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",
|
||||
},
|
||||
align: "inline-start"
|
||||
}
|
||||
});
|
||||
|
||||
export type InputGroupAddonAlign = VariantProps<typeof inputGroupAddonVariants>["align"];
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
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",
|
||||
"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: {
|
||||
size: "xs",
|
||||
},
|
||||
size: "xs"
|
||||
}
|
||||
});
|
||||
|
||||
export type InputGroupButtonSize = VariantProps<typeof inputGroupButtonVariants>["size"];
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
type InputType = Exclude<HTMLInputTypeAttribute, "file">;
|
||||
|
||||
type Props = WithElementRef<
|
||||
Omit<HTMLInputAttributes, "type"> &
|
||||
({ type: "file"; files?: FileList } | { type?: InputType; files?: undefined })
|
||||
Omit<HTMLInputAttributes, "type"> & ({ type: "file"; files?: FileList } | { type?: InputType; files?: undefined })
|
||||
>;
|
||||
|
||||
let {
|
||||
|
||||
@@ -10,11 +10,6 @@
|
||||
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={ref}
|
||||
data-slot="item-actions"
|
||||
class={cn("flex items-center gap-2", className)}
|
||||
{...restProps}
|
||||
>
|
||||
<div bind:this={ref} data-slot="item-actions" class={cn("flex items-center gap-2", className)} {...restProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
variant: {
|
||||
default: "bg-transparent",
|
||||
icon: "bg-muted size-8 rounded-sm border [&_svg:not([class*='size-'])]:size-4",
|
||||
image: "size-10 overflow-hidden rounded-sm [&_img]:size-full [&_img]:object-cover",
|
||||
},
|
||||
image: "size-10 overflow-hidden rounded-sm [&_img]:size-full [&_img]:object-cover"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
variant: "default"
|
||||
}
|
||||
});
|
||||
|
||||
export type ItemMediaVariant = VariantProps<typeof itemMediaVariants>["variant"];
|
||||
|
||||
@@ -3,17 +3,7 @@
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { ComponentProps } from "svelte";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: ComponentProps<typeof Separator> = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: ComponentProps<typeof Separator> = $props();
|
||||
</script>
|
||||
|
||||
<Separator
|
||||
bind:ref
|
||||
data-slot="item-separator"
|
||||
orientation="horizontal"
|
||||
class={cn("my-0", className)}
|
||||
{...restProps}
|
||||
/>
|
||||
<Separator bind:ref data-slot="item-separator" orientation="horizontal" class={cn("my-0", className)} {...restProps} />
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
variant: {
|
||||
default: "bg-transparent",
|
||||
outline: "border-border",
|
||||
muted: "bg-muted/50",
|
||||
muted: "bg-muted/50"
|
||||
},
|
||||
size: {
|
||||
default: "gap-4 p-4",
|
||||
sm: "gap-2.5 px-4 py-3",
|
||||
},
|
||||
sm: "gap-2.5 px-4 py-3"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
size: "default"
|
||||
}
|
||||
});
|
||||
|
||||
export type ItemSize = VariantProps<typeof itemVariants>["size"];
|
||||
@@ -47,7 +47,7 @@
|
||||
"data-slot": "item",
|
||||
"data-variant": variant,
|
||||
"data-size": size,
|
||||
...restProps,
|
||||
...restProps
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Label as LabelPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: LabelPrimitive.RootProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: LabelPrimitive.RootProps = $props();
|
||||
</script>
|
||||
|
||||
<LabelPrimitive.Root
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: NavigationMenuPrimitive.ContentProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: NavigationMenuPrimitive.ContentProps = $props();
|
||||
</script>
|
||||
|
||||
<NavigationMenuPrimitive.Content
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: NavigationMenuPrimitive.IndicatorProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: NavigationMenuPrimitive.IndicatorProps = $props();
|
||||
</script>
|
||||
|
||||
<NavigationMenuPrimitive.Indicator
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: NavigationMenuPrimitive.ItemProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: NavigationMenuPrimitive.ItemProps = $props();
|
||||
</script>
|
||||
|
||||
<NavigationMenuPrimitive.Item
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: NavigationMenuPrimitive.LinkProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: NavigationMenuPrimitive.LinkProps = $props();
|
||||
</script>
|
||||
|
||||
<NavigationMenuPrimitive.Link
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: NavigationMenuPrimitive.ListProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: NavigationMenuPrimitive.ListProps = $props();
|
||||
</script>
|
||||
|
||||
<NavigationMenuPrimitive.List
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { NavigationMenu as NavigationMenuPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: NavigationMenuPrimitive.ViewportProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: NavigationMenuPrimitive.ViewportProps = $props();
|
||||
</script>
|
||||
|
||||
<div class={cn("absolute start-0 top-full isolate z-50 flex justify-center")}>
|
||||
|
||||
@@ -18,10 +18,7 @@
|
||||
bind:ref
|
||||
data-slot="navigation-menu"
|
||||
data-viewport={viewport}
|
||||
class={cn(
|
||||
"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
|
||||
className
|
||||
)}
|
||||
class={cn("group/navigation-menu relative flex max-w-max flex-1 items-center justify-center", className)}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
|
||||
@@ -2,16 +2,7 @@
|
||||
import { cn } from "$lib/utils.js";
|
||||
import { Popover as PopoverPrimitive } from "bits-ui";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: PopoverPrimitive.TriggerProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: PopoverPrimitive.TriggerProps = $props();
|
||||
</script>
|
||||
|
||||
<PopoverPrimitive.Trigger
|
||||
bind:ref
|
||||
data-slot="popover-trigger"
|
||||
class={cn("", className)}
|
||||
{...restProps}
|
||||
/>
|
||||
<PopoverPrimitive.Trigger bind:ref data-slot="popover-trigger" class={cn("", className)} {...restProps} />
|
||||
|
||||
@@ -22,9 +22,7 @@
|
||||
{#snippet children({ checked })}
|
||||
<div data-slot="radio-group-indicator" class="relative flex items-center justify-center">
|
||||
{#if checked}
|
||||
<CircleIcon
|
||||
class="fill-primary absolute start-1/2 top-1/2 size-2 -translate-x-1/2 -translate-y-1/2"
|
||||
/>
|
||||
<CircleIcon class="fill-primary absolute start-1/2 top-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
@@ -34,9 +34,7 @@
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
class={cn(
|
||||
"h-(--bits-select-anchor-height) w-full min-w-(--bits-select-anchor-width) scroll-my-1 p-1"
|
||||
)}
|
||||
class={cn("h-(--bits-select-anchor-height) w-full min-w-(--bits-select-anchor-width) scroll-my-1 p-1")}
|
||||
>
|
||||
{@render children?.()}
|
||||
</SelectPrimitive.Viewport>
|
||||
|
||||
@@ -3,11 +3,7 @@
|
||||
import { Separator } from "$lib/components/ui/separator/index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: SeparatorPrimitive.RootProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: SeparatorPrimitive.RootProps = $props();
|
||||
</script>
|
||||
|
||||
<Separator
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
value = $bindable(),
|
||||
...restProps
|
||||
}: SelectPrimitive.RootProps = $props();
|
||||
let { open = $bindable(false), value = $bindable(), ...restProps }: SelectPrimitive.RootProps = $props();
|
||||
</script>
|
||||
|
||||
<SelectPrimitive.Root bind:open bind:value={value as never} {...restProps} />
|
||||
|
||||
@@ -5,14 +5,16 @@
|
||||
variants: {
|
||||
side: {
|
||||
top: "data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
|
||||
bottom: "data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
|
||||
bottom:
|
||||
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
|
||||
left: "data-[state=closed]:slide-out-to-start data-[state=open]:slide-in-from-start inset-y-0 start-0 h-full w-3/4 border-e sm:max-w-sm",
|
||||
right: "data-[state=closed]:slide-out-to-end data-[state=open]:slide-in-from-end inset-y-0 end-0 h-full w-3/4 border-s sm:max-w-sm",
|
||||
},
|
||||
right:
|
||||
"data-[state=closed]:slide-out-to-end data-[state=open]:slide-in-from-end inset-y-0 end-0 h-full w-3/4 border-s sm:max-w-sm"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
side: "right",
|
||||
},
|
||||
side: "right"
|
||||
}
|
||||
});
|
||||
|
||||
export type Side = VariantProps<typeof sheetVariants>["side"];
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: SheetPrimitive.DescriptionProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: SheetPrimitive.DescriptionProps = $props();
|
||||
</script>
|
||||
|
||||
<SheetPrimitive.Description
|
||||
|
||||
@@ -10,11 +10,6 @@
|
||||
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={ref}
|
||||
data-slot="sheet-footer"
|
||||
class={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
||||
{...restProps}
|
||||
>
|
||||
<div bind:this={ref} data-slot="sheet-footer" class={cn("mt-auto flex flex-col gap-2 p-4", className)} {...restProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
@@ -10,11 +10,6 @@
|
||||
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={ref}
|
||||
data-slot="sheet-header"
|
||||
class={cn("flex flex-col gap-1.5 p-4", className)}
|
||||
{...restProps}
|
||||
>
|
||||
<div bind:this={ref} data-slot="sheet-header" class={cn("flex flex-col gap-1.5 p-4", className)} {...restProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: SheetPrimitive.OverlayProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: SheetPrimitive.OverlayProps = $props();
|
||||
</script>
|
||||
|
||||
<SheetPrimitive.Overlay
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: SheetPrimitive.TitleProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: SheetPrimitive.TitleProps = $props();
|
||||
</script>
|
||||
|
||||
<SheetPrimitive.Title
|
||||
|
||||
@@ -53,9 +53,7 @@ class SidebarState {
|
||||
};
|
||||
|
||||
toggle = () => {
|
||||
return this.#isMobile.current
|
||||
? (this.openMobile = !this.openMobile)
|
||||
: this.setOpen(!this.open);
|
||||
return this.#isMobile.current ? (this.openMobile = !this.openMobile) : this.setOpen(!this.open);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
),
|
||||
"data-slot": "sidebar-group-action",
|
||||
"data-sidebar": "group-action",
|
||||
...restProps,
|
||||
...restProps
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
),
|
||||
"data-slot": "sidebar-group-label",
|
||||
"data-sidebar": "group-label",
|
||||
...restProps,
|
||||
...restProps
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
),
|
||||
"data-slot": "sidebar-menu-action",
|
||||
"data-sidebar": "menu-action",
|
||||
...restProps,
|
||||
...restProps
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -7,23 +7,21 @@
|
||||
variant: {
|
||||
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
||||
outline:
|
||||
"bg-background hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shadow-[0_0_0_1px_var(--sidebar-border)] hover:shadow-[0_0_0_1px_var(--sidebar-accent)]",
|
||||
"bg-background hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shadow-[0_0_0_1px_var(--sidebar-border)] hover:shadow-[0_0_0_1px_var(--sidebar-accent)]"
|
||||
},
|
||||
size: {
|
||||
default: "h-8 text-sm",
|
||||
sm: "h-7 text-xs",
|
||||
lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!",
|
||||
},
|
||||
lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
size: "default"
|
||||
}
|
||||
});
|
||||
|
||||
export type SidebarMenuButtonVariant = VariantProps<
|
||||
typeof sidebarMenuButtonVariants
|
||||
>["variant"];
|
||||
export type SidebarMenuButtonVariant = VariantProps<typeof sidebarMenuButtonVariants>["variant"];
|
||||
export type SidebarMenuButtonSize = VariantProps<typeof sidebarMenuButtonVariants>["size"];
|
||||
</script>
|
||||
|
||||
@@ -63,7 +61,7 @@
|
||||
"data-sidebar": "menu-button",
|
||||
"data-size": size,
|
||||
"data-active": isActive,
|
||||
...restProps,
|
||||
...restProps
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"data-sidebar": "menu-sub-button",
|
||||
"data-size": size,
|
||||
"data-active": isActive,
|
||||
...restProps,
|
||||
...restProps
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
import * as Tooltip from "$lib/components/ui/tooltip/index.js";
|
||||
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import {
|
||||
SIDEBAR_COOKIE_MAX_AGE,
|
||||
SIDEBAR_COOKIE_NAME,
|
||||
SIDEBAR_WIDTH,
|
||||
SIDEBAR_WIDTH_ICON,
|
||||
} from "./constants.js";
|
||||
import { SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME, SIDEBAR_WIDTH, SIDEBAR_WIDTH_ICON } from "./constants.js";
|
||||
import { setSidebar } from "./context.svelte.js";
|
||||
|
||||
let {
|
||||
@@ -31,7 +26,7 @@
|
||||
|
||||
// This sets the cookie to keep the sidebar state.
|
||||
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -41,10 +36,7 @@
|
||||
<div
|
||||
data-slot="sidebar-wrapper"
|
||||
style="--sidebar-width: {SIDEBAR_WIDTH}; --sidebar-width-icon: {SIDEBAR_WIDTH_ICON}; {style}"
|
||||
class={cn(
|
||||
"group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
|
||||
className
|
||||
)}
|
||||
class={cn("group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full", className)}
|
||||
bind:this={ref}
|
||||
{...restProps}
|
||||
>
|
||||
|
||||
@@ -3,11 +3,7 @@
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { ComponentProps } from "svelte";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: ComponentProps<typeof Separator> = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: ComponentProps<typeof Separator> = $props();
|
||||
</script>
|
||||
|
||||
<Separator
|
||||
|
||||
@@ -24,20 +24,14 @@
|
||||
|
||||
{#if collapsible === "none"}
|
||||
<div
|
||||
class={cn(
|
||||
"bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
|
||||
className
|
||||
)}
|
||||
class={cn("bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col", className)}
|
||||
bind:this={ref}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{:else if sidebar.isMobile}
|
||||
<Sheet.Root
|
||||
bind:open={() => sidebar.openMobile, (v) => sidebar.setOpenMobile(v)}
|
||||
{...restProps}
|
||||
>
|
||||
<Sheet.Root bind:open={() => sidebar.openMobile, (v) => sidebar.setOpenMobile(v)} {...restProps}>
|
||||
<Sheet.Content
|
||||
data-sidebar="sidebar"
|
||||
data-slot="sidebar"
|
||||
|
||||
@@ -6,9 +6,4 @@
|
||||
let { class: className, ...restProps }: ComponentProps<typeof Loader2Icon> = $props();
|
||||
</script>
|
||||
|
||||
<Loader2Icon
|
||||
role="status"
|
||||
aria-label="Loading"
|
||||
class={cn("size-4 animate-spin", className)}
|
||||
{...restProps}
|
||||
/>
|
||||
<Loader2Icon role="status" aria-label="Loading" class={cn("size-4 animate-spin", className)} {...restProps} />
|
||||
|
||||
@@ -10,11 +10,6 @@
|
||||
}: WithElementRef<HTMLAttributes<HTMLTableSectionElement>> = $props();
|
||||
</script>
|
||||
|
||||
<tbody
|
||||
bind:this={ref}
|
||||
data-slot="table-body"
|
||||
class={cn("[&_tr:last-child]:border-0", className)}
|
||||
{...restProps}
|
||||
>
|
||||
<tbody bind:this={ref} data-slot="table-body" class={cn("[&_tr:last-child]:border-0", className)} {...restProps}>
|
||||
{@render children?.()}
|
||||
</tbody>
|
||||
|
||||
@@ -2,21 +2,13 @@
|
||||
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||
import type { HTMLTdAttributes } from "svelte/elements";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLTdAttributes> = $props();
|
||||
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLTdAttributes> = $props();
|
||||
</script>
|
||||
|
||||
<td
|
||||
bind:this={ref}
|
||||
data-slot="table-cell"
|
||||
class={cn(
|
||||
"bg-clip-padding p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pe-0",
|
||||
className
|
||||
)}
|
||||
class={cn("bg-clip-padding p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pe-0", className)}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||
import type { HTMLThAttributes } from "svelte/elements";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLThAttributes> = $props();
|
||||
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLThAttributes> = $props();
|
||||
</script>
|
||||
|
||||
<th
|
||||
|
||||
@@ -10,11 +10,6 @@
|
||||
}: WithElementRef<HTMLAttributes<HTMLTableSectionElement>> = $props();
|
||||
</script>
|
||||
|
||||
<thead
|
||||
bind:this={ref}
|
||||
data-slot="table-header"
|
||||
class={cn("[&_tr]:border-b", className)}
|
||||
{...restProps}
|
||||
>
|
||||
<thead bind:this={ref} data-slot="table-header" class={cn("[&_tr]:border-b", className)} {...restProps}>
|
||||
{@render children?.()}
|
||||
</thead>
|
||||
|
||||
@@ -11,12 +11,7 @@
|
||||
</script>
|
||||
|
||||
<div data-slot="table-container" class="relative w-full overflow-x-auto">
|
||||
<table
|
||||
bind:this={ref}
|
||||
data-slot="table"
|
||||
class={cn("w-full caption-bottom text-sm", className)}
|
||||
{...restProps}
|
||||
>
|
||||
<table bind:this={ref} data-slot="table" class={cn("w-full caption-bottom text-sm", className)} {...restProps}>
|
||||
{@render children?.()}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -2,16 +2,7 @@
|
||||
import { Tabs as TabsPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: TabsPrimitive.ContentProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: TabsPrimitive.ContentProps = $props();
|
||||
</script>
|
||||
|
||||
<TabsPrimitive.Content
|
||||
bind:ref
|
||||
data-slot="tabs-content"
|
||||
class={cn("flex-1 outline-none", className)}
|
||||
{...restProps}
|
||||
/>
|
||||
<TabsPrimitive.Content bind:ref data-slot="tabs-content" class={cn("flex-1 outline-none", className)} {...restProps} />
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Tabs as TabsPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: TabsPrimitive.ListProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: TabsPrimitive.ListProps = $props();
|
||||
</script>
|
||||
|
||||
<TabsPrimitive.List
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
import { Tabs as TabsPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: TabsPrimitive.TriggerProps = $props();
|
||||
let { ref = $bindable(null), class: className, ...restProps }: TabsPrimitive.TriggerProps = $props();
|
||||
</script>
|
||||
|
||||
<TabsPrimitive.Trigger
|
||||
|
||||
@@ -10,10 +10,4 @@
|
||||
}: TabsPrimitive.RootProps = $props();
|
||||
</script>
|
||||
|
||||
<TabsPrimitive.Root
|
||||
bind:ref
|
||||
bind:value
|
||||
data-slot="tabs"
|
||||
class={cn("flex flex-col gap-2", className)}
|
||||
{...restProps}
|
||||
/>
|
||||
<TabsPrimitive.Root bind:ref bind:value data-slot="tabs" class={cn("flex flex-col gap-2", className)} {...restProps} />
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import Root from "./toggle.svelte";
|
||||
export {
|
||||
toggleVariants,
|
||||
type ToggleSize,
|
||||
type ToggleVariant,
|
||||
type ToggleVariants,
|
||||
} from "./toggle.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Toggle,
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
<script lang="ts" module>
|
||||
import { type VariantProps, tv } from "tailwind-variants";
|
||||
|
||||
export const toggleVariants = tv({
|
||||
base: "hover:bg-muted hover:text-muted-foreground data-[state=on]:bg-accent data-[state=on]:text-accent-foreground 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 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-transparent",
|
||||
outline:
|
||||
"border-input hover:bg-accent hover:text-accent-foreground border bg-transparent shadow-xs",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 min-w-9 px-2",
|
||||
sm: "h-8 min-w-8 px-1.5",
|
||||
lg: "h-10 min-w-10 px-2.5",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
});
|
||||
|
||||
export type ToggleVariant = VariantProps<typeof toggleVariants>["variant"];
|
||||
export type ToggleSize = VariantProps<typeof toggleVariants>["size"];
|
||||
export type ToggleVariants = VariantProps<typeof toggleVariants>;
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { Toggle as TogglePrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
pressed = $bindable(false),
|
||||
class: className,
|
||||
size = "default",
|
||||
variant = "default",
|
||||
...restProps
|
||||
}: TogglePrimitive.RootProps & {
|
||||
variant?: ToggleVariant;
|
||||
size?: ToggleSize;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<TogglePrimitive.Root
|
||||
bind:ref
|
||||
bind:pressed
|
||||
data-slot="toggle"
|
||||
class={cn(toggleVariants({ variant, size }), className)}
|
||||
{...restProps}
|
||||
/>
|
||||
@@ -90,4 +90,3 @@
|
||||
"We have sent a code to your email. Please enter it below to confirm your login": "Abbiamo inviato un codice alla tua email. Inseriscilo qui sotto per confermare l'accesso",
|
||||
"You are logged in as %email": "Sei connesso come %email"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
const kenerAPITypeData = {
|
||||
url: "https://kener.ing",
|
||||
method: "GET",
|
||||
headers: [],
|
||||
body: "",
|
||||
timeout: 10000,
|
||||
eval: "(async function (statusCode, responseTime, responseRaw, modules) { \n\tlet statusCodeShort = Math.floor(statusCode/100);\n if(statusCode == 429 || (statusCodeShort >=2 && statusCodeShort <= 3)) {\n return {\n\t\t\tstatus: 'UP',\n\t\t\tlatency: responseTime,\n }\n } \n\treturn {\n\t\tstatus: 'DOWN',\n\t\tlatency: responseTime,\n\t}\n})",
|
||||
allowSelfSignedCert: false,
|
||||
};
|
||||
|
||||
const defaultMonitorSettings = {
|
||||
uptime_formula_numerator: "up + maintenance",
|
||||
uptime_formula_denominator: "up + maintenance + down + degraded",
|
||||
};
|
||||
|
||||
let seedMonitorData = [
|
||||
{
|
||||
tag: "earth",
|
||||
@@ -15,6 +30,8 @@ let seedMonitorData = [
|
||||
day_degraded_minimum_count: 1,
|
||||
day_down_minimum_count: 1,
|
||||
include_degraded_in_downtime: "NO",
|
||||
is_hidden: "NO",
|
||||
monitor_settings_json: JSON.stringify(defaultMonitorSettings),
|
||||
},
|
||||
{
|
||||
tag: "kener",
|
||||
@@ -29,12 +46,12 @@ let seedMonitorData = [
|
||||
monitor_type: "API",
|
||||
down_trigger: null,
|
||||
degraded_trigger: null,
|
||||
type_data: `{"url":"https://kener.ing","method":"GET","headers":[],"body":"","timeout":10000,"eval":"(async function (statusCode, responseTime, responseRaw, modules) {\n\tlet statusCodeShort = Math.floor(statusCode/100);\n if(statusCode == 429 || (statusCodeShort >=2 && statusCodeShort <= 3)) {\n return {\n\t\t\tstatus: 'UP',\n\t\t\tlatency: responseTime,\n }\n } \n\treturn {\n\t\tstatus: 'DOWN',\n\t\tlatency: responseTime,\n\t}\n})","allowSelfSignedCert":false}`,
|
||||
type_data: JSON.stringify(kenerAPITypeData),
|
||||
day_degraded_minimum_count: 1,
|
||||
day_down_minimum_count: 1,
|
||||
include_degraded_in_downtime: "NO",
|
||||
is_hidden: "NO",
|
||||
monitor_setting_json: `{"uptime_formula_numerator":"up + maintenance","uptime_formula_denominator":"up + maintenance + down + degraded"}`,
|
||||
monitor_settings_json: JSON.stringify(defaultMonitorSettings),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -5,13 +5,7 @@ import * as cheerio from "cheerio";
|
||||
import { DefaultAPIEval } from "../../anywhere.js";
|
||||
import version from "../../version.js";
|
||||
import https from "https";
|
||||
import type { ApiMonitor, EvalResponse } from "../types/monitor.js";
|
||||
|
||||
interface MonitoringResult {
|
||||
status: string;
|
||||
latency: number;
|
||||
type: string;
|
||||
}
|
||||
import type { ApiMonitor, EvalResponse, MonitoringResult } from "../types/monitor.js";
|
||||
|
||||
class ApiCall {
|
||||
monitor: ApiMonitor;
|
||||
@@ -99,6 +93,7 @@ class ApiCall {
|
||||
}
|
||||
let statusCode = 500;
|
||||
let latency = 0;
|
||||
let errorMessage = "";
|
||||
let resp = "";
|
||||
let timeoutError = false;
|
||||
const start = Date.now();
|
||||
@@ -113,10 +108,11 @@ class ApiCall {
|
||||
response?: { status?: number; data?: string };
|
||||
};
|
||||
console.log(`Error in apiCall ${tag}`, error.message);
|
||||
|
||||
errorMessage = error.message || "Unknown error";
|
||||
// Better timeout detection
|
||||
if (error.code === "ECONNABORTED" || (error.message && error.message.includes("timeout"))) {
|
||||
timeoutError = true;
|
||||
errorMessage = "Request timed out";
|
||||
console.log(`Timeout in api call for ${tag} at ${Math.floor(Date.now() / 1000)}`);
|
||||
}
|
||||
|
||||
@@ -149,6 +145,7 @@ class ApiCall {
|
||||
);
|
||||
evalResp = await evalFunction(statusCode, latency, resp, modules);
|
||||
} catch (error: unknown) {
|
||||
errorMessage += ` | Eval error: ${(error as Error).message}`;
|
||||
console.log(`Error in monitorEval for ${tag}`, (error as Error).message);
|
||||
}
|
||||
|
||||
@@ -176,6 +173,7 @@ class ApiCall {
|
||||
status: DOWN,
|
||||
latency: latency,
|
||||
type: ERROR,
|
||||
error_message: errorMessage,
|
||||
};
|
||||
if (evalResp.status !== undefined && evalResp.status !== null) {
|
||||
toWrite.status = evalResp.status;
|
||||
|
||||
@@ -4,6 +4,7 @@ export interface MonitoringResult {
|
||||
status: string;
|
||||
latency: number;
|
||||
type: string;
|
||||
error_message?: string;
|
||||
}
|
||||
|
||||
export interface MonitoringResultTS {
|
||||
|
||||
@@ -22,7 +22,7 @@ export const load: LayoutServerLoad = async ({ cookies, request, url }) => {
|
||||
|
||||
let isSetupComplete = await IsSetupComplete();
|
||||
if (!isSetupComplete) {
|
||||
throw redirect(302, resolve(`/manage/setup`));
|
||||
throw redirect(302, resolve(`/account/signin`));
|
||||
}
|
||||
|
||||
let isLoggedIn = await IsLoggedInSession(cookies);
|
||||
|
||||
@@ -2,6 +2,8 @@ import i18n from "$lib/i18n/server";
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
import MobileDetect from "mobile-detect";
|
||||
import type { LayoutServerLoad } from "./$types";
|
||||
import { IsEmailSetup, CheckInvitationExists } from "$lib/server/controllers/controller.js";
|
||||
import { INVITE_VERIFY_EMAIL } from "$lib/server/constants.js";
|
||||
|
||||
import { resolve } from "$app/paths";
|
||||
import {
|
||||
@@ -23,6 +25,11 @@ export const load: LayoutServerLoad = async ({ cookies, request, url }) => {
|
||||
|
||||
let isLoggedIn = await IsLoggedInSession(cookies);
|
||||
|
||||
//if user not set throw redirect to signin
|
||||
if (!isLoggedIn.user) {
|
||||
throw redirect(302, "/account/logout");
|
||||
}
|
||||
|
||||
const siteData = await GetAllSiteData();
|
||||
let localTz = "UTC";
|
||||
const localTzCookie = cookies.get("localTz");
|
||||
@@ -42,6 +49,9 @@ export const load: LayoutServerLoad = async ({ cookies, request, url }) => {
|
||||
|
||||
// const emailSubscriptionTrigger = await GetSubscriptionTriggerByEmail();
|
||||
return {
|
||||
userDb: isLoggedIn.user,
|
||||
siteStatusColors,
|
||||
canSendEmail: IsEmailSetup(),
|
||||
activeInvitationExists: await CheckInvitationExists(isLoggedIn.user.id, INVITE_VERIFY_EMAIL),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
import { ValidateIpAddress, IsValidHost, IsValidNameServer, IsValidURL, IsValidPort } from "$lib/clientTools";
|
||||
import { GAMEDIG_SOCKET_TIMEOUT } from "$lib/anywhere";
|
||||
import * as InputGroup from "$lib/components/ui/input-group/index.js";
|
||||
|
||||
import type { MonitoringResult } from "$lib/server/types/monitor.js";
|
||||
// Type-specific components
|
||||
import {
|
||||
MonitorApi,
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
// Test monitor state
|
||||
let testingMonitor = $state(false);
|
||||
let testResult = $state<{ status?: string; latency?: number; error?: string } | null>(null);
|
||||
let testResult = $state<MonitoringResult | null>(null);
|
||||
|
||||
// Modify monitoring data state
|
||||
let modifyingData = $state(false);
|
||||
@@ -311,7 +311,8 @@
|
||||
if (m.type_data) {
|
||||
try {
|
||||
typeData = JSON.parse(m.type_data);
|
||||
} catch {
|
||||
} catch (e: any) {
|
||||
console.error("Failed to parse type_data:", e);
|
||||
typeData = {};
|
||||
}
|
||||
}
|
||||
@@ -323,7 +324,8 @@
|
||||
uptime_formula_numerator: settings.uptime_formula_numerator || "up + maintenance",
|
||||
uptime_formula_denominator: settings.uptime_formula_denominator || "up + maintenance + down + degraded"
|
||||
};
|
||||
} catch {
|
||||
} catch (e: any) {
|
||||
console.error("Failed to parse monitor_settings_json:", e);
|
||||
// Keep defaults
|
||||
}
|
||||
}
|
||||
@@ -601,7 +603,7 @@
|
||||
const result = await response.json();
|
||||
testResult = result;
|
||||
} catch (e) {
|
||||
testResult = { error: "Failed to test monitor" };
|
||||
testResult = { error_message: "Failed to test monitor", status: "NO_DATA", latency: 0, type: "error" };
|
||||
} finally {
|
||||
testingMonitor = false;
|
||||
}
|
||||
@@ -944,7 +946,73 @@
|
||||
{/if}
|
||||
</div>
|
||||
</Card.Content>
|
||||
<Card.Footer class="flex justify-end">
|
||||
<Card.Footer class="flex justify-between gap-2">
|
||||
<Dialog.Root
|
||||
onOpenChange={(e) => {
|
||||
if (e) testMonitor();
|
||||
}}
|
||||
>
|
||||
<Dialog.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Button {...props} variant="secondary">
|
||||
<PlayIcon class="size-4" />
|
||||
Test Monitor
|
||||
</Button>
|
||||
{/snippet}
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Content>
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>
|
||||
{#if testingMonitor}
|
||||
Running Test
|
||||
{:else if testResult}
|
||||
Test Result
|
||||
{:else}
|
||||
Test Monitor
|
||||
{/if}
|
||||
</Dialog.Title>
|
||||
</Dialog.Header>
|
||||
<div class="flex flex-col justify-center gap-2">
|
||||
{#if testingMonitor}
|
||||
<div class="flex flex-col items-center gap-2 py-8">
|
||||
<Loader class="size-8 animate-spin" />
|
||||
<p class="text-muted-foreground mt-4 text-center">
|
||||
Please wait while the test is being performed...
|
||||
</p>
|
||||
</div>
|
||||
{:else if testResult}
|
||||
<div class="mt-4 flex flex-col gap-4">
|
||||
{#if testResult.error_message}
|
||||
<div class="bg-destructive/10 text-destructive rounded-md p-3 text-sm font-medium">
|
||||
{testResult.error_message}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="rounded-lg border p-4 text-center">
|
||||
<div class="text-muted-foreground text-xs uppercase">Status</div>
|
||||
<div class="mt-1 text-2xl font-bold text-{testResult.status.toLowerCase()}">
|
||||
{testResult.status}
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-lg border p-4 text-center">
|
||||
<div class="text-muted-foreground text-xs uppercase">Response Time</div>
|
||||
<div class="mt-1 text-2xl font-bold">
|
||||
{testResult.latency}ms
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<Button variant="outline" size="sm" onclick={testMonitor} disabled={testingMonitor}>
|
||||
<PlayIcon class="mr-2 size-3" />
|
||||
Run Test Again
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
<Button onclick={saveTypeSettings} disabled={savingType || !isTypeSettingsValid}>
|
||||
{#if savingType}
|
||||
<Loader class="mr-2 size-4 animate-spin" />
|
||||
@@ -1045,59 +1113,6 @@
|
||||
</Card.Root>
|
||||
{/if}
|
||||
|
||||
<!-- Test Monitor Card -->
|
||||
{#if !isNew && monitor.monitor_type && monitor.monitor_type !== "NONE"}
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title class="flex items-center gap-2">
|
||||
<PlayIcon class="size-5" />
|
||||
Test Monitor
|
||||
</Card.Title>
|
||||
<Card.Description>Run a test to check the current status of this monitor</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="flex items-center gap-4">
|
||||
<Button onclick={testMonitor} disabled={testingMonitor}>
|
||||
{#if testingMonitor}
|
||||
<Loader class="mr-2 size-4 animate-spin" />
|
||||
Testing...
|
||||
{:else}
|
||||
<PlayIcon class="mr-2 size-4" />
|
||||
Run Test
|
||||
{/if}
|
||||
</Button>
|
||||
{#if testResult}
|
||||
<div class="flex-1 rounded-md border p-3">
|
||||
{#if testResult.error}
|
||||
<p class="text-destructive text-sm">{testResult.error}</p>
|
||||
{:else if testResult.status !== undefined && testResult.latency !== undefined}
|
||||
<div class="flex items-center gap-4">
|
||||
<div>
|
||||
<p class="text-muted-foreground text-xs">Status</p>
|
||||
<p
|
||||
class="font-medium"
|
||||
class:text-green-500={testResult.status === "UP"}
|
||||
class:text-yellow-500={testResult.status === "DEGRADED"}
|
||||
class:text-red-500={testResult.status === "DOWN"}
|
||||
>
|
||||
{testResult.status}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-muted-foreground text-xs">Response Time</p>
|
||||
<p class="font-medium">{testResult.latency}ms</p>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<p class="text-muted-foreground text-sm">No result available</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
{/if}
|
||||
|
||||
<!-- Modify Monitoring Data Card -->
|
||||
{#if !isNew}
|
||||
<Card.Root>
|
||||
|
||||
@@ -1,14 +1,138 @@
|
||||
<script lang="ts">
|
||||
import CreditCardIcon from "@lucide/svelte/icons/credit-card";
|
||||
import DotsVerticalIcon from "@lucide/svelte/icons/camera";
|
||||
import LogoutIcon from "@lucide/svelte/icons/home";
|
||||
import DotsVerticalIcon from "@lucide/svelte/icons/ellipsis-vertical";
|
||||
import LogoutIcon from "@lucide/svelte/icons/log-out";
|
||||
import NotificationIcon from "@lucide/svelte/icons/bell";
|
||||
import UserCircleIcon from "@lucide/svelte/icons/user-circle";
|
||||
import CheckIcon from "@lucide/svelte/icons/check";
|
||||
import LoaderIcon from "@lucide/svelte/icons/loader";
|
||||
import * as Avatar from "$lib/components/ui/avatar/index.js";
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
|
||||
import * as Sidebar from "$lib/components/ui/sidebar/index.js";
|
||||
let { user }: { user: { name: string; email: string; avatar: string } } = $props();
|
||||
import * as Dialog from "$lib/components/ui/dialog/index.js";
|
||||
import { Input } from "$lib/components/ui/input/index.js";
|
||||
import { Label } from "$lib/components/ui/label/index.js";
|
||||
import { Button } from "$lib/components/ui/button/index.js";
|
||||
import { page } from "$app/state";
|
||||
import { base } from "$app/paths";
|
||||
import type { UserRecordPublic } from "$lib/server/types/db";
|
||||
|
||||
let user = $state<UserRecordPublic>(page.data.userDb);
|
||||
let nameAbbr = $derived(
|
||||
user.name
|
||||
.split(" ")
|
||||
.map((n) => n[0])
|
||||
.join("")
|
||||
.slice(0, 2)
|
||||
.toUpperCase()
|
||||
);
|
||||
|
||||
const sidebar = Sidebar.useSidebar();
|
||||
|
||||
// Account dialog state
|
||||
let accountDialogOpen = $state(false);
|
||||
let myName = $state(user.name);
|
||||
let myPassword = $state("");
|
||||
let plainPassword = $state("");
|
||||
let savingName = $state(false);
|
||||
let resettingPass = $state(false);
|
||||
let nameError = $state("");
|
||||
let passwordError = $state("");
|
||||
let nameSuccess = $state(false);
|
||||
let passwordSuccess = $state(false);
|
||||
|
||||
// Password validation
|
||||
let hasDigit = $derived(/\d/.test(myPassword));
|
||||
let hasLowercase = $derived(/[a-z]/.test(myPassword));
|
||||
let hasUppercase = $derived(/[A-Z]/.test(myPassword));
|
||||
let hasLetter = $derived(/[a-zA-Z]/.test(myPassword));
|
||||
let hasMinLength = $derived(myPassword.length >= 8);
|
||||
let passwordsMatch = $derived(myPassword === plainPassword && myPassword !== "");
|
||||
let isPasswordValid = $derived(
|
||||
hasDigit && hasLowercase && hasUppercase && hasLetter && hasMinLength && passwordsMatch
|
||||
);
|
||||
|
||||
// Role badge styling
|
||||
let roleBadgeClass = $derived(() => {
|
||||
switch (user.role) {
|
||||
case "admin":
|
||||
return "bg-pink-100 text-pink-800 dark:bg-pink-900 dark:text-pink-300";
|
||||
case "editor":
|
||||
return "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300";
|
||||
case "member":
|
||||
return "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300";
|
||||
default:
|
||||
return "bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300";
|
||||
}
|
||||
});
|
||||
|
||||
async function saveName() {
|
||||
savingName = true;
|
||||
nameError = "";
|
||||
nameSuccess = false;
|
||||
try {
|
||||
const response = await fetch(base + "/manage/api", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
action: "updateUser",
|
||||
data: { updateValue: myName, updateKey: "name" }
|
||||
})
|
||||
});
|
||||
const resp = await response.json();
|
||||
if (resp.error) {
|
||||
nameError = resp.error;
|
||||
} else {
|
||||
user.name = myName;
|
||||
nameSuccess = true;
|
||||
setTimeout(() => (nameSuccess = false), 2000);
|
||||
}
|
||||
} catch {
|
||||
nameError = "Error while saving name";
|
||||
} finally {
|
||||
savingName = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function updatePassword() {
|
||||
resettingPass = true;
|
||||
passwordError = "";
|
||||
passwordSuccess = false;
|
||||
try {
|
||||
const response = await fetch(base + "/manage/api", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
action: "updatePassword",
|
||||
data: { newPassword: myPassword, newPlainPassword: plainPassword }
|
||||
})
|
||||
});
|
||||
const resp = await response.json();
|
||||
if (resp.error) {
|
||||
passwordError = resp.error;
|
||||
} else {
|
||||
myPassword = "";
|
||||
plainPassword = "";
|
||||
passwordSuccess = true;
|
||||
setTimeout(() => (passwordSuccess = false), 2000);
|
||||
}
|
||||
} catch {
|
||||
passwordError = "Error while updating password";
|
||||
} finally {
|
||||
resettingPass = false;
|
||||
}
|
||||
}
|
||||
|
||||
function openAccountDialog() {
|
||||
myName = user.name;
|
||||
myPassword = "";
|
||||
plainPassword = "";
|
||||
nameError = "";
|
||||
passwordError = "";
|
||||
nameSuccess = false;
|
||||
passwordSuccess = false;
|
||||
accountDialogOpen = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Sidebar.Menu>
|
||||
@@ -22,11 +146,12 @@
|
||||
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
||||
>
|
||||
<Avatar.Root class="size-8 rounded-lg grayscale">
|
||||
<Avatar.Image src={user.avatar} alt={user.name} />
|
||||
<Avatar.Fallback class="rounded-lg">CN</Avatar.Fallback>
|
||||
<Avatar.Fallback class="rounded-lg">
|
||||
{nameAbbr}
|
||||
</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
<div class="grid flex-1 text-start text-sm leading-tight">
|
||||
<span class="truncate font-medium">{user.name}</span>
|
||||
<span class="truncate font-medium">{nameAbbr}</span>
|
||||
<span class="text-muted-foreground truncate text-xs">
|
||||
{user.email}
|
||||
</span>
|
||||
@@ -44,8 +169,7 @@
|
||||
<DropdownMenu.Label class="p-0 font-normal">
|
||||
<div class="flex items-center gap-2 px-1 py-1.5 text-start text-sm">
|
||||
<Avatar.Root class="size-8 rounded-lg">
|
||||
<Avatar.Image src={user.avatar} alt={user.name} />
|
||||
<Avatar.Fallback class="rounded-lg">CN</Avatar.Fallback>
|
||||
<Avatar.Fallback class="rounded-lg">{nameAbbr}</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
<div class="grid flex-1 text-start text-sm leading-tight">
|
||||
<span class="truncate font-medium">{user.name}</span>
|
||||
@@ -57,25 +181,134 @@
|
||||
</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={openAccountDialog}>
|
||||
<UserCircleIcon />
|
||||
Account
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>
|
||||
<CreditCardIcon />
|
||||
Billing
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>
|
||||
<NotificationIcon />
|
||||
Notifications
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item>
|
||||
<DropdownMenu.Item onSelect={() => (window.location.href = `${base}/account/logout`)}>
|
||||
{#snippet child({ props })}
|
||||
<Button {...props} variant="ghost" href="/account/logout" class="w-full justify-start">
|
||||
<LogoutIcon />
|
||||
Log out
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</Sidebar.MenuItem>
|
||||
</Sidebar.Menu>
|
||||
|
||||
<Dialog.Root bind:open={accountDialogOpen}>
|
||||
<Dialog.Content class="max-w-md">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title class="flex flex-col justify-between">
|
||||
<span>Account Settings</span>
|
||||
</Dialog.Title>
|
||||
<Dialog.Description class="flex flex-col gap-2">
|
||||
<span> Manage your profile information. </span>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-foreground rounded-sm font-medium">
|
||||
{user.email}
|
||||
</span>
|
||||
<span class="text-foreground rounded-sm font-medium uppercase">
|
||||
{user.role}
|
||||
</span>
|
||||
</div>
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<div class="flex flex-col gap-6 py-4">
|
||||
<!-- Name Section -->
|
||||
|
||||
<form
|
||||
class="flex flex-col gap-3"
|
||||
onsubmit={(e) => {
|
||||
e.preventDefault();
|
||||
saveName();
|
||||
}}
|
||||
>
|
||||
<Label for="account-name">Name</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input id="account-name" bind:value={myName} placeholder="Your name" disabled={savingName} class="flex-1" />
|
||||
<Button type="submit" disabled={savingName || !myName.trim()}>
|
||||
{#if savingName}
|
||||
<LoaderIcon class="size-4 animate-spin" />
|
||||
{:else if nameSuccess}
|
||||
<CheckIcon class="size-4" />
|
||||
{:else}
|
||||
Save
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
{#if nameError}
|
||||
<p class="text-destructive text-sm">{nameError}</p>
|
||||
{/if}
|
||||
</form>
|
||||
|
||||
<hr />
|
||||
|
||||
<!-- Password Section -->
|
||||
<form
|
||||
class="flex flex-col gap-3"
|
||||
onsubmit={(e) => {
|
||||
e.preventDefault();
|
||||
updatePassword();
|
||||
}}
|
||||
>
|
||||
<Label for="new-password">Change Password</Label>
|
||||
<Input
|
||||
id="new-password"
|
||||
type="password"
|
||||
bind:value={myPassword}
|
||||
placeholder="New Password"
|
||||
disabled={resettingPass}
|
||||
/>
|
||||
<Input
|
||||
id="confirm-password"
|
||||
type="password"
|
||||
bind:value={plainPassword}
|
||||
placeholder="Confirm Password"
|
||||
disabled={resettingPass}
|
||||
/>
|
||||
|
||||
<div class="text-muted-foreground text-xs">
|
||||
<p class="mb-1 font-medium">Password requirements:</p>
|
||||
<ul class="grid grid-cols-2 gap-1">
|
||||
<li class:text-green-500={hasDigit}>
|
||||
{#if hasDigit}<CheckIcon class="inline size-3" />{/if} One digit
|
||||
</li>
|
||||
<li class:text-green-500={hasLowercase}>
|
||||
{#if hasLowercase}<CheckIcon class="inline size-3" />{/if} One lowercase
|
||||
</li>
|
||||
<li class:text-green-500={hasUppercase}>
|
||||
{#if hasUppercase}<CheckIcon class="inline size-3" />{/if} One uppercase
|
||||
</li>
|
||||
<li class:text-green-500={hasMinLength}>
|
||||
{#if hasMinLength}<CheckIcon class="inline size-3" />{/if} 8+ characters
|
||||
</li>
|
||||
<li class:text-green-500={passwordsMatch}>
|
||||
{#if passwordsMatch}<CheckIcon class="inline size-3" />{/if} Passwords match
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<Button type="submit" disabled={resettingPass || !isPasswordValid}>
|
||||
{#if resettingPass}
|
||||
<LoaderIcon class="mr-2 size-4 animate-spin" />
|
||||
Updating...
|
||||
{:else if passwordSuccess}
|
||||
<CheckIcon class="mr-2 size-4" />
|
||||
Updated!
|
||||
{:else}
|
||||
Update Password
|
||||
{/if}
|
||||
</Button>
|
||||
{#if passwordError}
|
||||
<p class="text-destructive text-sm">{passwordError}</p>
|
||||
{/if}
|
||||
</form>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ main {
|
||||
}
|
||||
|
||||
.note {
|
||||
@apply mt-4 rounded-md border bg-background p-3 text-sm shadow-sm;
|
||||
@apply bg-background mt-4 rounded-md border p-3 text-sm shadow-sm;
|
||||
}
|
||||
.note.danger {
|
||||
border: 1px solid #e3342f;
|
||||
|
||||
Reference in New Issue
Block a user