diff --git a/bot/app/web/frontend/jsconfig.json b/bot/app/web/frontend/jsconfig.json
new file mode 100644
index 0000000..145e4ec
--- /dev/null
+++ b/bot/app/web/frontend/jsconfig.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "$lib/*": ["src/lib/*"],
+ "$components/*": ["src/lib/components/*"]
+ }
+ },
+ "include": ["src/**/*"]
+}
diff --git a/bot/app/web/frontend/src/App.svelte b/bot/app/web/frontend/src/App.svelte
index eb6c111..de4f3db 100644
--- a/bot/app/web/frontend/src/App.svelte
+++ b/bot/app/web/frontend/src/App.svelte
@@ -4,7 +4,7 @@
import { createBillingStore } from "./lib/webapp/stores/billingStore.js";
import { createDevicesStore } from "./lib/webapp/stores/devicesStore.js";
import { createAccountStore } from "./lib/webapp/stores/accountStore.js";
- import { Tooltip } from "bits-ui";
+ import { Tooltip } from "$components/ui/primitives.js";
import BrandMark from "./BrandMark.svelte";
import PreviewBoard from "./PreviewBoard.svelte";
diff --git a/bot/app/web/frontend/src/PreviewBoard.svelte b/bot/app/web/frontend/src/PreviewBoard.svelte
index feb94e0..cac8087 100644
--- a/bot/app/web/frontend/src/PreviewBoard.svelte
+++ b/bot/app/web/frontend/src/PreviewBoard.svelte
@@ -19,8 +19,8 @@
Zap,
} from "lucide-svelte";
- import Button from "./lib/components/ui/button.svelte";
- import Card from "./lib/components/ui/card.svelte";
+ import Button from "$components/ui/button.svelte";
+ import Card from "$components/ui/card.svelte";
import BackTitle from "./preview/BackTitle.svelte";
import PhoneFrame from "./preview/PhoneFrame.svelte";
import PreviewMethods from "./preview/PreviewMethods.svelte";
diff --git a/bot/app/web/frontend/src/admin/AdminPanel.svelte b/bot/app/web/frontend/src/admin/AdminPanel.svelte
index baeebe3..66c5fb8 100644
--- a/bot/app/web/frontend/src/admin/AdminPanel.svelte
+++ b/bot/app/web/frontend/src/admin/AdminPanel.svelte
@@ -20,7 +20,7 @@
UsersRound,
} from "lucide-svelte";
import { onMount, setContext } from "svelte";
- import { Select } from "bits-ui";
+ import { Select } from "$components/ui/primitives.js";
import BrandMark from "../BrandMark.svelte";
import AdsSection from "./sections/AdsSection.svelte";
diff --git a/bot/app/web/frontend/src/admin/sections/AdsSection.svelte b/bot/app/web/frontend/src/admin/sections/AdsSection.svelte
index fc044dd..7dbe733 100644
--- a/bot/app/web/frontend/src/admin/sections/AdsSection.svelte
+++ b/bot/app/web/frontend/src/admin/sections/AdsSection.svelte
@@ -1,8 +1,8 @@
{#if statsError}
-
{at("stats_error", { error: statsError }, "")}
+ {at("stats_error", { error: statsError }, "")}
{:else if showSkeleton}
-
-
-
{at("stats_section_audience", {}, "")}
-
-
+
+
+
{#each Array(3) as _, i (i)}
@@ -144,7 +148,7 @@
{/each}
-
+
@@ -156,9 +160,7 @@
-
-
{at("stats_recent_payments", {}, "")}
-
+
-
+
{:else if stats}
-
-
-
{at("stats_section_audience", {}, "")}
- {at("stats_section_audience_hint", {}, "")}
-
+
+
-
+
{at("stats_label_users", {}, "")}
@@ -243,12 +245,12 @@
-
+
-
-
{at("stats_section_revenue", {}, "")}
- {at("stats_section_revenue_hint", {}, "")}
-
+
@@ -356,14 +358,10 @@
-
-
{at("stats_section_panel", {}, "")}
- {#if panelPayload?.error}
- {at("stats_panel_unavailable", {}, "")}
- {:else if panelMetrics}
- {at("stats_section_panel_hint", {}, "")}
- {/if}
-
+
{#if panelPayload?.error}
{at("stats_panel_unavailable_detail", {}, "")}
@@ -511,10 +509,10 @@
{:else}
- {at("no_data", {}, "")}
+ {at("no_data", {}, "")}
{/if}
-
+
{/if}
diff --git a/bot/app/web/frontend/src/admin/sections/TariffEditorModal.svelte b/bot/app/web/frontend/src/admin/sections/TariffEditorModal.svelte
index e2ac879..9f2ff32 100644
--- a/bot/app/web/frontend/src/admin/sections/TariffEditorModal.svelte
+++ b/bot/app/web/frontend/src/admin/sections/TariffEditorModal.svelte
@@ -1,6 +1,6 @@
+
+
+
+
diff --git a/bot/app/web/frontend/src/lib/components/patterns/admin/AdminDashboardStack.svelte b/bot/app/web/frontend/src/lib/components/patterns/admin/AdminDashboardStack.svelte
new file mode 100644
index 0000000..b3f1b33
--- /dev/null
+++ b/bot/app/web/frontend/src/lib/components/patterns/admin/AdminDashboardStack.svelte
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/bot/app/web/frontend/src/lib/components/patterns/admin/AdminEmptyState.svelte b/bot/app/web/frontend/src/lib/components/patterns/admin/AdminEmptyState.svelte
new file mode 100644
index 0000000..c9fc8b4
--- /dev/null
+++ b/bot/app/web/frontend/src/lib/components/patterns/admin/AdminEmptyState.svelte
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/bot/app/web/frontend/src/lib/components/patterns/admin/AdminSectionHeader.svelte b/bot/app/web/frontend/src/lib/components/patterns/admin/AdminSectionHeader.svelte
new file mode 100644
index 0000000..1cd5acc
--- /dev/null
+++ b/bot/app/web/frontend/src/lib/components/patterns/admin/AdminSectionHeader.svelte
@@ -0,0 +1,11 @@
+
+
+
+
{title}
+ {#if description}
+ {description}
+ {/if}
+
diff --git a/bot/app/web/frontend/src/lib/components/patterns/admin/index.js b/bot/app/web/frontend/src/lib/components/patterns/admin/index.js
new file mode 100644
index 0000000..a29622f
--- /dev/null
+++ b/bot/app/web/frontend/src/lib/components/patterns/admin/index.js
@@ -0,0 +1,4 @@
+export { default as AdminDashboardGrid } from "./AdminDashboardGrid.svelte";
+export { default as AdminDashboardStack } from "./AdminDashboardStack.svelte";
+export { default as AdminEmptyState } from "./AdminEmptyState.svelte";
+export { default as AdminSectionHeader } from "./AdminSectionHeader.svelte";
diff --git a/bot/app/web/frontend/src/lib/components/shadcn/badge.svelte b/bot/app/web/frontend/src/lib/components/ui/badge.svelte
similarity index 61%
rename from bot/app/web/frontend/src/lib/components/shadcn/badge.svelte
rename to bot/app/web/frontend/src/lib/components/ui/badge.svelte
index b8b0a39..5a77bec 100644
--- a/bot/app/web/frontend/src/lib/components/shadcn/badge.svelte
+++ b/bot/app/web/frontend/src/lib/components/ui/badge.svelte
@@ -1,7 +1,7 @@
{#if href}
-
+
{:else}
-