@treeline-money/plugin-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +266 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/package.json +39 -0
- package/styles/plugin.css +503 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Treeline Plugin SDK
|
|
3
|
+
*
|
|
4
|
+
* TypeScript types and interfaces for building Treeline plugins.
|
|
5
|
+
* Install: npm install @treeline-money/plugin-sdk
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Plugin manifest describing the plugin's metadata and permissions.
|
|
11
|
+
*/
|
|
12
|
+
export interface PluginManifest {
|
|
13
|
+
/** Unique identifier (e.g., "subscriptions", "goals") */
|
|
14
|
+
id: string;
|
|
15
|
+
/** Display name */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Version string (semver) */
|
|
18
|
+
version: string;
|
|
19
|
+
/** Short description */
|
|
20
|
+
description: string;
|
|
21
|
+
/** Author name or organization */
|
|
22
|
+
author: string;
|
|
23
|
+
/** Optional icon (emoji or icon name) */
|
|
24
|
+
icon?: string;
|
|
25
|
+
/** Permissions this plugin requires */
|
|
26
|
+
permissions?: PluginPermissions;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Permissions a plugin can request.
|
|
30
|
+
*/
|
|
31
|
+
export interface PluginPermissions {
|
|
32
|
+
/** Table permissions for this plugin */
|
|
33
|
+
tables?: {
|
|
34
|
+
/** Tables this plugin can SELECT from */
|
|
35
|
+
read?: string[];
|
|
36
|
+
/** Tables this plugin can INSERT/UPDATE/DELETE */
|
|
37
|
+
write?: string[];
|
|
38
|
+
/** Tables this plugin can CREATE/DROP (must match sys_plugin_{id}_* pattern) */
|
|
39
|
+
create?: string[];
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The SDK object passed to plugin views via props.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```svelte
|
|
47
|
+
* <script lang="ts">
|
|
48
|
+
* import type { PluginSDK } from '@treeline-money/plugin-sdk';
|
|
49
|
+
*
|
|
50
|
+
* interface Props {
|
|
51
|
+
* sdk: PluginSDK;
|
|
52
|
+
* }
|
|
53
|
+
* const { sdk }: Props = $props();
|
|
54
|
+
*
|
|
55
|
+
* // Query transactions
|
|
56
|
+
* const transactions = await sdk.query('SELECT * FROM transactions LIMIT 10');
|
|
57
|
+
*
|
|
58
|
+
* // Show a toast
|
|
59
|
+
* sdk.toast.success('Data loaded!');
|
|
60
|
+
* </script>
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export interface PluginSDK {
|
|
64
|
+
/**
|
|
65
|
+
* Execute a read-only SQL query against the database.
|
|
66
|
+
* @param sql - SQL SELECT query
|
|
67
|
+
* @returns Array of row objects
|
|
68
|
+
*/
|
|
69
|
+
query: <T = Record<string, unknown>>(sql: string) => Promise<T[]>;
|
|
70
|
+
/**
|
|
71
|
+
* Execute a write SQL query (INSERT/UPDATE/DELETE).
|
|
72
|
+
* Restricted to tables allowed in plugin permissions.
|
|
73
|
+
* @param sql - SQL write query
|
|
74
|
+
* @returns Object with rowsAffected count
|
|
75
|
+
*/
|
|
76
|
+
execute: (sql: string) => Promise<{
|
|
77
|
+
rowsAffected: number;
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* Toast notification methods.
|
|
81
|
+
*/
|
|
82
|
+
toast: {
|
|
83
|
+
/** Show an info toast */
|
|
84
|
+
show: (message: string, description?: string) => void;
|
|
85
|
+
/** Show a success toast */
|
|
86
|
+
success: (message: string, description?: string) => void;
|
|
87
|
+
/** Show an error toast */
|
|
88
|
+
error: (message: string, description?: string) => void;
|
|
89
|
+
/** Show a warning toast */
|
|
90
|
+
warning: (message: string, description?: string) => void;
|
|
91
|
+
/** Show an info toast */
|
|
92
|
+
info: (message: string, description?: string) => void;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Navigate to another view.
|
|
96
|
+
* @param viewId - The view ID to open
|
|
97
|
+
* @param props - Optional props to pass to the view
|
|
98
|
+
*/
|
|
99
|
+
openView: (viewId: string, props?: Record<string, unknown>) => void;
|
|
100
|
+
/**
|
|
101
|
+
* Subscribe to data refresh events (called after sync/import).
|
|
102
|
+
* @param callback - Function to call when data is refreshed
|
|
103
|
+
* @returns Unsubscribe function
|
|
104
|
+
*/
|
|
105
|
+
onDataRefresh: (callback: () => void) => () => void;
|
|
106
|
+
/**
|
|
107
|
+
* Emit a data refresh event. Call this after modifying data
|
|
108
|
+
* so other views can update.
|
|
109
|
+
*/
|
|
110
|
+
emitDataRefresh: () => void;
|
|
111
|
+
/**
|
|
112
|
+
* Update the badge count shown on this plugin's sidebar item.
|
|
113
|
+
* @param count - Badge count (0 or undefined to hide)
|
|
114
|
+
*/
|
|
115
|
+
updateBadge: (count: number | undefined) => void;
|
|
116
|
+
/**
|
|
117
|
+
* Theme utilities.
|
|
118
|
+
*/
|
|
119
|
+
theme: {
|
|
120
|
+
/** Get current theme ("light" or "dark") */
|
|
121
|
+
current: () => "light" | "dark";
|
|
122
|
+
/** Subscribe to theme changes */
|
|
123
|
+
subscribe: (callback: (theme: string) => void) => () => void;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Platform-aware modifier key display string.
|
|
127
|
+
* Returns "Cmd" on Mac, "Ctrl" on Windows/Linux.
|
|
128
|
+
*/
|
|
129
|
+
modKey: "Cmd" | "Ctrl";
|
|
130
|
+
/**
|
|
131
|
+
* Format a keyboard shortcut for display.
|
|
132
|
+
* Converts "mod+p" to "⌘P" on Mac or "Ctrl+P" on Windows.
|
|
133
|
+
* @param shortcut - Shortcut string (e.g., "mod+shift+p")
|
|
134
|
+
*/
|
|
135
|
+
formatShortcut: (shortcut: string) => string;
|
|
136
|
+
/**
|
|
137
|
+
* Plugin settings (persisted, scoped to plugin ID).
|
|
138
|
+
*/
|
|
139
|
+
settings: {
|
|
140
|
+
/** Get all settings for this plugin */
|
|
141
|
+
get: <T extends Record<string, unknown>>() => Promise<T>;
|
|
142
|
+
/** Save settings for this plugin */
|
|
143
|
+
set: <T extends Record<string, unknown>>(settings: T) => Promise<void>;
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Plugin state (ephemeral, scoped to plugin ID).
|
|
147
|
+
* Use for runtime state that doesn't need to persist.
|
|
148
|
+
*/
|
|
149
|
+
state: {
|
|
150
|
+
/** Read plugin state */
|
|
151
|
+
read: <T>() => Promise<T | null>;
|
|
152
|
+
/** Write plugin state */
|
|
153
|
+
write: <T>(state: T) => Promise<void>;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Currency formatting utilities.
|
|
157
|
+
*/
|
|
158
|
+
currency: {
|
|
159
|
+
/** Format amount with currency symbol (e.g., "$1,234.56") */
|
|
160
|
+
format: (amount: number, currency?: string) => string;
|
|
161
|
+
/** Format compactly for large amounts (e.g., "$1.2M") */
|
|
162
|
+
formatCompact: (amount: number, currency?: string) => string;
|
|
163
|
+
/** Format just the number without symbol (e.g., "1,234.56") */
|
|
164
|
+
formatAmount: (amount: number) => string;
|
|
165
|
+
/** Get symbol for a currency code (e.g., "USD" -> "$") */
|
|
166
|
+
getSymbol: (currency: string) => string;
|
|
167
|
+
/** Get the user's configured currency code */
|
|
168
|
+
getUserCurrency: () => string;
|
|
169
|
+
/** List of supported currency codes */
|
|
170
|
+
supportedCurrencies: string[];
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Sidebar section definition.
|
|
175
|
+
*/
|
|
176
|
+
export interface SidebarSection {
|
|
177
|
+
/** Section ID */
|
|
178
|
+
id: string;
|
|
179
|
+
/** Section title (shown as header) */
|
|
180
|
+
title: string;
|
|
181
|
+
/** Sort order (lower = higher) */
|
|
182
|
+
order: number;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Sidebar item definition.
|
|
186
|
+
*/
|
|
187
|
+
export interface SidebarItem {
|
|
188
|
+
/** Unique ID */
|
|
189
|
+
id: string;
|
|
190
|
+
/** Display label */
|
|
191
|
+
label: string;
|
|
192
|
+
/** Icon (emoji or icon name) */
|
|
193
|
+
icon: string;
|
|
194
|
+
/** Section this belongs to */
|
|
195
|
+
sectionId: string;
|
|
196
|
+
/** View to open when clicked */
|
|
197
|
+
viewId: string;
|
|
198
|
+
/** Keyboard shortcut hint */
|
|
199
|
+
shortcut?: string;
|
|
200
|
+
/** Sort order within section */
|
|
201
|
+
order?: number;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* View definition for plugin views.
|
|
205
|
+
*/
|
|
206
|
+
export interface ViewDefinition {
|
|
207
|
+
/** Unique view ID */
|
|
208
|
+
id: string;
|
|
209
|
+
/** Display name (shown in tab) */
|
|
210
|
+
name: string;
|
|
211
|
+
/** Icon for tab */
|
|
212
|
+
icon: string;
|
|
213
|
+
/**
|
|
214
|
+
* Mount function that renders into the target element.
|
|
215
|
+
* @param target - DOM element to render into
|
|
216
|
+
* @param props - Props including the SDK
|
|
217
|
+
* @returns Cleanup function to call when unmounting
|
|
218
|
+
*/
|
|
219
|
+
mount: (target: HTMLElement, props: {
|
|
220
|
+
sdk: PluginSDK;
|
|
221
|
+
}) => () => void;
|
|
222
|
+
/** Can multiple instances be open? */
|
|
223
|
+
allowMultiple?: boolean;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Command definition for the command palette.
|
|
227
|
+
*/
|
|
228
|
+
export interface Command {
|
|
229
|
+
/** Unique command ID */
|
|
230
|
+
id: string;
|
|
231
|
+
/** Display name */
|
|
232
|
+
name: string;
|
|
233
|
+
/** Category for grouping */
|
|
234
|
+
category?: string;
|
|
235
|
+
/** Keyboard shortcut */
|
|
236
|
+
shortcut?: string;
|
|
237
|
+
/** Function to execute */
|
|
238
|
+
execute: () => void | Promise<void>;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Plugin context provided during activation.
|
|
242
|
+
*/
|
|
243
|
+
export interface PluginContext {
|
|
244
|
+
/** Register a sidebar section */
|
|
245
|
+
registerSidebarSection: (section: SidebarSection) => void;
|
|
246
|
+
/** Register a sidebar item */
|
|
247
|
+
registerSidebarItem: (item: SidebarItem) => void;
|
|
248
|
+
/** Register a view */
|
|
249
|
+
registerView: (view: ViewDefinition) => void;
|
|
250
|
+
/** Register a command */
|
|
251
|
+
registerCommand: (command: Command) => void;
|
|
252
|
+
/** Open a view */
|
|
253
|
+
openView: (viewId: string, props?: Record<string, unknown>) => void;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Plugin interface that all plugins must implement.
|
|
257
|
+
*/
|
|
258
|
+
export interface Plugin {
|
|
259
|
+
/** Plugin manifest */
|
|
260
|
+
manifest: PluginManifest;
|
|
261
|
+
/** Called when plugin is activated */
|
|
262
|
+
activate: (ctx: PluginContext) => void | Promise<void>;
|
|
263
|
+
/** Called when plugin is deactivated */
|
|
264
|
+
deactivate?: () => void | Promise<void>;
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@treeline-money/plugin-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript SDK for building Treeline plugins",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./styles": "./styles/plugin.css"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"styles"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"treeline",
|
|
25
|
+
"plugin",
|
|
26
|
+
"sdk",
|
|
27
|
+
"personal-finance"
|
|
28
|
+
],
|
|
29
|
+
"author": "Treeline Money",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/treeline-money/treeline.git",
|
|
34
|
+
"directory": "plugin-sdk"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"typescript": "^5.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Treeline Plugin Styles
|
|
3
|
+
*
|
|
4
|
+
* Shared CSS classes for community plugins to match the app's look and feel.
|
|
5
|
+
* Import this in your plugin: import '@treeline-money/plugin-sdk/styles'
|
|
6
|
+
*
|
|
7
|
+
* All classes are prefixed with `tl-` to avoid conflicts.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/* ============================================================================
|
|
11
|
+
* Layout
|
|
12
|
+
* ============================================================================ */
|
|
13
|
+
|
|
14
|
+
.tl-view {
|
|
15
|
+
height: 100%;
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
background: var(--bg-primary);
|
|
19
|
+
color: var(--text-primary);
|
|
20
|
+
font-family: var(--font-sans, system-ui, -apple-system, sans-serif);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.tl-header {
|
|
24
|
+
display: flex;
|
|
25
|
+
justify-content: space-between;
|
|
26
|
+
align-items: flex-start;
|
|
27
|
+
padding: var(--spacing-lg, 16px);
|
|
28
|
+
background: var(--bg-secondary);
|
|
29
|
+
border-bottom: 1px solid var(--border-primary);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.tl-header-left {
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
gap: var(--spacing-xs, 4px);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.tl-header-right {
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: var(--spacing-md, 12px);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.tl-title {
|
|
45
|
+
font-size: 16px;
|
|
46
|
+
font-weight: 600;
|
|
47
|
+
color: var(--text-primary);
|
|
48
|
+
margin: 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.tl-subtitle {
|
|
52
|
+
font-size: 13px;
|
|
53
|
+
color: var(--text-muted);
|
|
54
|
+
margin: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.tl-content {
|
|
58
|
+
flex: 1;
|
|
59
|
+
overflow-y: auto;
|
|
60
|
+
padding: var(--spacing-lg, 16px);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* ============================================================================
|
|
64
|
+
* Buttons
|
|
65
|
+
* ============================================================================ */
|
|
66
|
+
|
|
67
|
+
.tl-btn {
|
|
68
|
+
display: inline-flex;
|
|
69
|
+
align-items: center;
|
|
70
|
+
justify-content: center;
|
|
71
|
+
gap: 6px;
|
|
72
|
+
padding: 8px 14px;
|
|
73
|
+
border-radius: var(--radius-sm, 4px);
|
|
74
|
+
font-size: 13px;
|
|
75
|
+
font-weight: 500;
|
|
76
|
+
cursor: pointer;
|
|
77
|
+
border: none;
|
|
78
|
+
transition: all 0.15s;
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.tl-btn:disabled {
|
|
83
|
+
opacity: 0.5;
|
|
84
|
+
cursor: not-allowed;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.tl-btn-primary {
|
|
88
|
+
background: var(--accent-primary);
|
|
89
|
+
color: var(--bg-primary);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.tl-btn-primary:hover:not(:disabled) {
|
|
93
|
+
opacity: 0.9;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.tl-btn-secondary {
|
|
97
|
+
background: var(--bg-tertiary);
|
|
98
|
+
color: var(--text-primary);
|
|
99
|
+
border: 1px solid var(--border-primary);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.tl-btn-secondary:hover:not(:disabled) {
|
|
103
|
+
background: var(--bg-secondary);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.tl-btn-danger {
|
|
107
|
+
background: var(--accent-danger);
|
|
108
|
+
color: white;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.tl-btn-danger:hover:not(:disabled) {
|
|
112
|
+
opacity: 0.9;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.tl-btn-text {
|
|
116
|
+
background: transparent;
|
|
117
|
+
color: var(--text-secondary);
|
|
118
|
+
padding: 4px 8px;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.tl-btn-text:hover:not(:disabled) {
|
|
122
|
+
color: var(--text-primary);
|
|
123
|
+
background: var(--bg-tertiary);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.tl-btn-icon {
|
|
127
|
+
width: 28px;
|
|
128
|
+
height: 28px;
|
|
129
|
+
padding: 0;
|
|
130
|
+
background: transparent;
|
|
131
|
+
border: none;
|
|
132
|
+
border-radius: var(--radius-sm, 4px);
|
|
133
|
+
color: var(--text-secondary);
|
|
134
|
+
cursor: pointer;
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
justify-content: center;
|
|
138
|
+
font-size: 14px;
|
|
139
|
+
transition: all 0.15s;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.tl-btn-icon:hover:not(:disabled) {
|
|
143
|
+
background: var(--bg-tertiary);
|
|
144
|
+
color: var(--text-primary);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* ============================================================================
|
|
148
|
+
* Cards
|
|
149
|
+
* ============================================================================ */
|
|
150
|
+
|
|
151
|
+
.tl-cards {
|
|
152
|
+
display: grid;
|
|
153
|
+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
154
|
+
gap: var(--spacing-md, 12px);
|
|
155
|
+
margin-bottom: var(--spacing-lg, 16px);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.tl-card {
|
|
159
|
+
background: var(--bg-secondary);
|
|
160
|
+
border: 1px solid var(--border-primary);
|
|
161
|
+
border-radius: var(--radius-md, 6px);
|
|
162
|
+
padding: var(--spacing-md, 12px);
|
|
163
|
+
display: flex;
|
|
164
|
+
flex-direction: column;
|
|
165
|
+
gap: var(--spacing-xs, 4px);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.tl-card-label {
|
|
169
|
+
font-size: 11px;
|
|
170
|
+
color: var(--text-muted);
|
|
171
|
+
text-transform: uppercase;
|
|
172
|
+
letter-spacing: 0.5px;
|
|
173
|
+
font-weight: 500;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.tl-card-value {
|
|
177
|
+
font-size: 24px;
|
|
178
|
+
font-weight: 600;
|
|
179
|
+
color: var(--text-primary);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.tl-card-value-sm {
|
|
183
|
+
font-size: 18px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* ============================================================================
|
|
187
|
+
* Tables
|
|
188
|
+
* ============================================================================ */
|
|
189
|
+
|
|
190
|
+
.tl-table-container {
|
|
191
|
+
overflow-x: auto;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.tl-table {
|
|
195
|
+
width: 100%;
|
|
196
|
+
border-collapse: collapse;
|
|
197
|
+
font-size: 13px;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.tl-table th {
|
|
201
|
+
text-align: left;
|
|
202
|
+
padding: var(--spacing-sm, 8px) var(--spacing-md, 12px);
|
|
203
|
+
font-size: 11px;
|
|
204
|
+
font-weight: 600;
|
|
205
|
+
color: var(--text-muted);
|
|
206
|
+
text-transform: uppercase;
|
|
207
|
+
letter-spacing: 0.5px;
|
|
208
|
+
border-bottom: 2px solid var(--border-primary);
|
|
209
|
+
white-space: nowrap;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.tl-table th.tl-sortable {
|
|
213
|
+
cursor: pointer;
|
|
214
|
+
user-select: none;
|
|
215
|
+
transition: color 0.15s;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.tl-table th.tl-sortable:hover {
|
|
219
|
+
color: var(--text-primary);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.tl-table th.tl-sorted {
|
|
223
|
+
color: var(--accent-primary);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.tl-table td {
|
|
227
|
+
padding: var(--spacing-sm, 8px) var(--spacing-md, 12px);
|
|
228
|
+
border-bottom: 1px solid var(--border-primary);
|
|
229
|
+
color: var(--text-primary);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.tl-table tbody tr:hover {
|
|
233
|
+
background: var(--bg-secondary);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.tl-table tbody tr.tl-selected {
|
|
237
|
+
background: var(--bg-active);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.tl-table tbody tr.tl-muted {
|
|
241
|
+
opacity: 0.5;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Table cell types */
|
|
245
|
+
.tl-cell-mono {
|
|
246
|
+
font-family: var(--font-mono);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.tl-cell-number {
|
|
250
|
+
font-family: var(--font-mono);
|
|
251
|
+
text-align: right;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.tl-cell-date {
|
|
255
|
+
color: var(--text-muted);
|
|
256
|
+
font-size: 12px;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.tl-cell-positive {
|
|
260
|
+
color: var(--color-positive);
|
|
261
|
+
font-family: var(--font-mono);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.tl-cell-negative {
|
|
265
|
+
color: var(--color-negative);
|
|
266
|
+
font-family: var(--font-mono);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.tl-cell-actions {
|
|
270
|
+
display: flex;
|
|
271
|
+
gap: var(--spacing-xs, 4px);
|
|
272
|
+
justify-content: flex-end;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* ============================================================================
|
|
276
|
+
* Badges
|
|
277
|
+
* ============================================================================ */
|
|
278
|
+
|
|
279
|
+
.tl-badge {
|
|
280
|
+
display: inline-block;
|
|
281
|
+
padding: 3px 8px;
|
|
282
|
+
background: var(--bg-tertiary);
|
|
283
|
+
color: var(--accent-primary);
|
|
284
|
+
font-size: 10px;
|
|
285
|
+
font-weight: 600;
|
|
286
|
+
border-radius: var(--radius-sm, 4px);
|
|
287
|
+
text-transform: uppercase;
|
|
288
|
+
letter-spacing: 0.3px;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.tl-badge-success {
|
|
292
|
+
background: rgba(63, 185, 80, 0.15);
|
|
293
|
+
color: var(--accent-success);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.tl-badge-warning {
|
|
297
|
+
background: rgba(210, 153, 34, 0.15);
|
|
298
|
+
color: var(--accent-warning);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.tl-badge-danger {
|
|
302
|
+
background: rgba(248, 81, 73, 0.15);
|
|
303
|
+
color: var(--accent-danger);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.tl-badge-muted {
|
|
307
|
+
background: var(--bg-tertiary);
|
|
308
|
+
color: var(--text-muted);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* ============================================================================
|
|
312
|
+
* Form Elements
|
|
313
|
+
* ============================================================================ */
|
|
314
|
+
|
|
315
|
+
.tl-input {
|
|
316
|
+
padding: 8px 12px;
|
|
317
|
+
background: var(--bg-primary);
|
|
318
|
+
border: 1px solid var(--border-primary);
|
|
319
|
+
border-radius: var(--radius-sm, 4px);
|
|
320
|
+
color: var(--text-primary);
|
|
321
|
+
font-size: 13px;
|
|
322
|
+
font-family: inherit;
|
|
323
|
+
transition: border-color 0.15s;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.tl-input:focus {
|
|
327
|
+
outline: none;
|
|
328
|
+
border-color: var(--accent-primary);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.tl-input::placeholder {
|
|
332
|
+
color: var(--text-muted);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.tl-select {
|
|
336
|
+
padding: 8px 28px 8px 12px;
|
|
337
|
+
background: var(--bg-primary);
|
|
338
|
+
border: 1px solid var(--border-primary);
|
|
339
|
+
border-radius: var(--radius-sm, 4px);
|
|
340
|
+
color: var(--text-primary);
|
|
341
|
+
font-size: 13px;
|
|
342
|
+
font-family: inherit;
|
|
343
|
+
appearance: none;
|
|
344
|
+
-webkit-appearance: none;
|
|
345
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%239ca3af' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
|
|
346
|
+
background-repeat: no-repeat;
|
|
347
|
+
background-position: right 8px center;
|
|
348
|
+
cursor: pointer;
|
|
349
|
+
transition: border-color 0.15s;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.tl-select:focus {
|
|
353
|
+
outline: none;
|
|
354
|
+
border-color: var(--accent-primary);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.tl-select option {
|
|
358
|
+
background: var(--bg-secondary);
|
|
359
|
+
color: var(--text-primary);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.tl-checkbox {
|
|
363
|
+
display: flex;
|
|
364
|
+
align-items: center;
|
|
365
|
+
gap: var(--spacing-sm, 8px);
|
|
366
|
+
font-size: 13px;
|
|
367
|
+
color: var(--text-secondary);
|
|
368
|
+
cursor: pointer;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.tl-checkbox input {
|
|
372
|
+
accent-color: var(--accent-primary);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.tl-label {
|
|
376
|
+
font-size: 12px;
|
|
377
|
+
font-weight: 500;
|
|
378
|
+
color: var(--text-secondary);
|
|
379
|
+
margin-bottom: var(--spacing-xs, 4px);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.tl-form-group {
|
|
383
|
+
display: flex;
|
|
384
|
+
flex-direction: column;
|
|
385
|
+
gap: var(--spacing-xs, 4px);
|
|
386
|
+
margin-bottom: var(--spacing-md, 12px);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* ============================================================================
|
|
390
|
+
* Empty State
|
|
391
|
+
* ============================================================================ */
|
|
392
|
+
|
|
393
|
+
.tl-empty {
|
|
394
|
+
display: flex;
|
|
395
|
+
flex-direction: column;
|
|
396
|
+
align-items: center;
|
|
397
|
+
justify-content: center;
|
|
398
|
+
text-align: center;
|
|
399
|
+
padding: var(--spacing-xl, 24px);
|
|
400
|
+
color: var(--text-muted);
|
|
401
|
+
min-height: 200px;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.tl-empty-icon {
|
|
405
|
+
font-size: 48px;
|
|
406
|
+
margin-bottom: var(--spacing-md, 12px);
|
|
407
|
+
opacity: 0.5;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.tl-empty-title {
|
|
411
|
+
font-size: 16px;
|
|
412
|
+
font-weight: 600;
|
|
413
|
+
color: var(--text-primary);
|
|
414
|
+
margin-bottom: var(--spacing-sm, 8px);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.tl-empty-message {
|
|
418
|
+
font-size: 13px;
|
|
419
|
+
max-width: 400px;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/* ============================================================================
|
|
423
|
+
* Loading State
|
|
424
|
+
* ============================================================================ */
|
|
425
|
+
|
|
426
|
+
.tl-loading {
|
|
427
|
+
display: flex;
|
|
428
|
+
flex-direction: column;
|
|
429
|
+
align-items: center;
|
|
430
|
+
justify-content: center;
|
|
431
|
+
padding: var(--spacing-xl, 24px);
|
|
432
|
+
color: var(--text-muted);
|
|
433
|
+
gap: var(--spacing-md, 12px);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.tl-spinner {
|
|
437
|
+
width: 24px;
|
|
438
|
+
height: 24px;
|
|
439
|
+
border: 2px solid var(--border-primary);
|
|
440
|
+
border-top-color: var(--accent-primary);
|
|
441
|
+
border-radius: 50%;
|
|
442
|
+
animation: tl-spin 0.8s linear infinite;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
@keyframes tl-spin {
|
|
446
|
+
to {
|
|
447
|
+
transform: rotate(360deg);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/* ============================================================================
|
|
452
|
+
* Utility Classes
|
|
453
|
+
* ============================================================================ */
|
|
454
|
+
|
|
455
|
+
.tl-mono {
|
|
456
|
+
font-family: var(--font-mono);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.tl-muted {
|
|
460
|
+
color: var(--text-muted);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.tl-positive {
|
|
464
|
+
color: var(--color-positive);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.tl-negative {
|
|
468
|
+
color: var(--color-negative);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.tl-text-sm {
|
|
472
|
+
font-size: 12px;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.tl-text-xs {
|
|
476
|
+
font-size: 11px;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.tl-font-semibold {
|
|
480
|
+
font-weight: 600;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.tl-truncate {
|
|
484
|
+
overflow: hidden;
|
|
485
|
+
text-overflow: ellipsis;
|
|
486
|
+
white-space: nowrap;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.tl-gap-sm {
|
|
490
|
+
gap: var(--spacing-sm, 8px);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
.tl-gap-md {
|
|
494
|
+
gap: var(--spacing-md, 12px);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.tl-mt-md {
|
|
498
|
+
margin-top: var(--spacing-md, 12px);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.tl-mb-md {
|
|
502
|
+
margin-bottom: var(--spacing-md, 12px);
|
|
503
|
+
}
|