@escalated-dev/escalated 0.8.0 → 0.11.1
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/LICENSE +21 -21
- package/README.md +388 -361
- package/package.json +85 -84
- package/src/components/ActiveChatsPanel.vue +246 -246
- package/src/components/AdminDashboard.stories.js +1423 -1423
- package/src/components/AttachmentList.vue +65 -65
- package/src/components/ChatActionBar.vue +226 -226
- package/src/components/ChatBubble.vue +162 -162
- package/src/components/ChatComposer.vue +308 -308
- package/src/components/ChatQueue.vue +222 -222
- package/src/components/ChatThread.vue +197 -197
- package/src/components/CustomTicketActions.stories.js +71 -0
- package/src/components/CustomTicketActions.vue +101 -0
- package/src/components/EscalatedLayout.vue +628 -604
- package/src/components/FollowButton.vue +20 -1
- package/src/components/MentionDropdown.vue +154 -154
- package/src/components/MetricComparison.vue +89 -89
- package/src/components/PercentileChart.vue +67 -67
- package/src/components/PeriodSelector.vue +98 -98
- package/src/components/PresenceIndicator.vue +228 -213
- package/src/components/ReplyComposer.vue +336 -336
- package/src/components/ReplyThread.vue +153 -153
- package/src/components/ReportChart.vue +395 -395
- package/src/components/ReportExportButton.vue +108 -108
- package/src/components/SaveViewDialog.vue +172 -172
- package/src/components/SavedViewSidebar.vue +208 -208
- package/src/components/SkillTagManager.vue +3 -0
- package/src/components/SnoozeButton.vue +247 -247
- package/src/components/TicketFilters.vue +270 -270
- package/src/components/TicketList.vue +655 -655
- package/src/components/TicketSidebar.vue +4 -0
- package/src/components/TicketSplitDialog.vue +98 -98
- package/src/components/TicketSubjects.stories.js +63 -0
- package/src/components/TicketSubjects.vue +107 -0
- package/src/components/TwoFactorSetup.vue +1 -37
- package/src/components/VariableTokenInput.vue +111 -111
- package/src/components/WorkflowActionConfig.vue +287 -287
- package/src/components/WorkflowActionList.vue +350 -350
- package/src/components/WorkflowConditionBuilder.vue +265 -265
- package/src/components/WorkflowTriggerSelector.vue +125 -125
- package/src/components/admin/newsletters/AnalyticsTiles.stories.js +14 -0
- package/src/components/admin/newsletters/AnalyticsTiles.vue +55 -0
- package/src/components/admin/newsletters/DeliveriesTable.stories.js +28 -0
- package/src/components/admin/newsletters/DeliveriesTable.vue +104 -0
- package/src/components/admin/newsletters/DynamicFilterBuilder.stories.js +11 -0
- package/src/components/admin/newsletters/DynamicFilterBuilder.vue +53 -0
- package/src/components/admin/newsletters/ListMemberTable.stories.js +12 -0
- package/src/components/admin/newsletters/ListMemberTable.vue +53 -0
- package/src/components/admin/newsletters/MarkdownEditor.stories.js +6 -0
- package/src/components/admin/newsletters/MarkdownEditor.vue +53 -0
- package/src/components/admin/newsletters/MergeFieldDropdown.stories.js +6 -0
- package/src/components/admin/newsletters/MergeFieldDropdown.vue +84 -0
- package/src/components/admin/newsletters/PreviewIframe.stories.js +7 -0
- package/src/components/admin/newsletters/PreviewIframe.vue +40 -0
- package/src/components/admin/newsletters/SummaryTiles.stories.js +8 -0
- package/src/components/admin/newsletters/SummaryTiles.vue +63 -0
- package/src/composables/useChat.js +187 -187
- package/src/composables/useI18n.js +102 -102
- package/src/composables/useMentions.js +134 -134
- package/src/composables/usePermissions.js +31 -0
- package/src/composables/useRealtime.js +182 -182
- package/src/index.js +85 -84
- package/src/locales/README.md +13 -13
- package/src/locales/ar.json +727 -727
- package/src/locales/de.json +690 -690
- package/src/locales/en.json +889 -729
- package/src/locales/es.json +691 -691
- package/src/locales/fr.json +691 -691
- package/src/locales/index.js +16 -16
- package/src/locales/it.json +727 -727
- package/src/locales/ja.json +727 -727
- package/src/locales/ko.json +727 -727
- package/src/locales/nl.json +727 -727
- package/src/locales/pl.json +727 -727
- package/src/locales/pt-BR.json +727 -727
- package/src/locales/ru.json +727 -727
- package/src/locales/tr.json +727 -727
- package/src/locales/zh-CN.json +727 -727
- package/src/pages/Admin/Automations/Form.vue +280 -0
- package/src/pages/Admin/Automations/Index.vue +230 -0
- package/src/pages/Admin/Newsletters/Compose.vue +192 -0
- package/src/pages/Admin/Newsletters/Edit.vue +24 -0
- package/src/pages/Admin/Newsletters/Index.vue +141 -0
- package/src/pages/Admin/Newsletters/Lists/Create.vue +64 -0
- package/src/pages/Admin/Newsletters/Lists/Index.vue +59 -0
- package/src/pages/Admin/Newsletters/Lists/Show.vue +53 -0
- package/src/pages/Admin/Newsletters/Settings.vue +85 -0
- package/src/pages/Admin/Newsletters/Show.vue +140 -0
- package/src/pages/Admin/Newsletters/Templates/Create.vue +11 -0
- package/src/pages/Admin/Newsletters/Templates/Index.vue +54 -0
- package/src/pages/Admin/Newsletters/Templates/Show.vue +65 -0
- package/src/pages/Admin/Newsletters/usePreview.js +44 -0
- package/src/pages/Admin/Plugins/Index.vue +10 -2
- package/src/pages/Admin/Reports/AgentDetail.vue +132 -132
- package/src/pages/Admin/Reports/AgentRanking.vue +246 -246
- package/src/pages/Admin/Reports/Cohorts.vue +180 -180
- package/src/pages/Admin/Reports/Comparison.vue +141 -141
- package/src/pages/Admin/Reports/Dashboard.vue +226 -226
- package/src/pages/Admin/Reports/ResolutionTimes.vue +164 -164
- package/src/pages/Admin/Reports/ResponseTimes.vue +164 -164
- package/src/pages/Admin/Reports/SlaTrends.vue +183 -183
- package/src/pages/Admin/Settings/DatabaseConnection.vue +228 -0
- package/src/pages/Admin/Settings/PublicTickets.vue +163 -0
- package/src/pages/Admin/Settings/SsoSettings.vue +157 -4
- package/src/pages/Admin/Settings/TwoFactor.vue +32 -6
- package/src/pages/Admin/Settings.vue +1008 -1008
- package/src/pages/Admin/Skills/Form.vue +30 -10
- package/src/pages/Admin/Tickets/Index.vue +126 -126
- package/src/pages/Admin/Tickets/Show.vue +254 -249
- package/src/pages/Admin/Users/Index.vue +145 -145
- package/src/pages/Admin/Webhooks/DeliveryLog.vue +1 -2
- package/src/pages/Admin/Workflows/Builder.vue +207 -207
- package/src/pages/Admin/Workflows/Form.vue +24 -0
- package/src/pages/Admin/Workflows/Index.vue +235 -235
- package/src/pages/Admin/Workflows/Logs.vue +286 -286
- package/src/pages/Agent/TicketIndex.vue +112 -112
- package/src/pages/Agent/TicketShow.vue +547 -494
- package/src/pages/Customer/Index.vue +56 -56
- package/src/pages/Customer/KnowledgeBase/Article.vue +129 -129
- package/src/pages/Plugin/Page.vue +61 -0
- package/src/plugin.js +175 -175
- package/src/utils/mentionHighlight.js +24 -24
- package/src/widget/EscalatedWidget.vue +804 -804
- package/src/widget/index.js +254 -254
package/src/plugin.js
CHANGED
|
@@ -1,175 +1,175 @@
|
|
|
1
|
-
import { markRaw } from 'vue';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* EscalatedPlugin — Vue plugin for integrating Escalated into your app's design system.
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* import { EscalatedPlugin } from '@escalated-dev/escalated'
|
|
8
|
-
* import AppLayout from '@/Layouts/AppLayout.vue'
|
|
9
|
-
*
|
|
10
|
-
* app.use(EscalatedPlugin, {
|
|
11
|
-
* layout: AppLayout,
|
|
12
|
-
* theme: {
|
|
13
|
-
* primary: '#3b82f6',
|
|
14
|
-
* radius: '0.75rem',
|
|
15
|
-
* }
|
|
16
|
-
* })
|
|
17
|
-
*/
|
|
18
|
-
export const EscalatedPlugin = {
|
|
19
|
-
install(app, options = {}) {
|
|
20
|
-
installRouteShim();
|
|
21
|
-
|
|
22
|
-
if (options.layout) {
|
|
23
|
-
app.provide('escalated-layout', markRaw(options.layout));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (options.theme) {
|
|
27
|
-
app.provide('escalated-theme', options.theme);
|
|
28
|
-
applyTheme(options.theme);
|
|
29
|
-
|
|
30
|
-
if (options.theme.panel) {
|
|
31
|
-
const panelConfig = options.theme.panel;
|
|
32
|
-
applyPanelTheme(panelConfig);
|
|
33
|
-
app.provide('escalated-panel', {
|
|
34
|
-
appName: panelConfig.appName || 'Escalated',
|
|
35
|
-
logo: panelConfig.logo || null,
|
|
36
|
-
mode: panelConfig.mode || 'dark',
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// 77 components in this package call the Ziggy `route()` helper (Laravel's
|
|
44
|
-
// named-route URL generator). Laravel hosts ship Ziggy and get `window.route`
|
|
45
|
-
// for free; other host frameworks (Rails, Django, NestJS, Phoenix, Symfony,
|
|
46
|
-
// Adonis, Go, .NET, Spring, WordPress) don't, and the call sites would
|
|
47
|
-
// otherwise throw a bare ReferenceError deep inside a component render with
|
|
48
|
-
// no hint at the cause.
|
|
49
|
-
//
|
|
50
|
-
// Install a stub that throws an informative error instead, so the host app's
|
|
51
|
-
// first failing request points at the actual missing dependency. Laravel hosts
|
|
52
|
-
// that already have Ziggy loaded are left alone.
|
|
53
|
-
function installRouteShim() {
|
|
54
|
-
if (typeof window === 'undefined') return;
|
|
55
|
-
if (typeof window.route === 'function') return;
|
|
56
|
-
|
|
57
|
-
window.route = function escalatedRouteShimMissing(name) {
|
|
58
|
-
throw new Error(
|
|
59
|
-
`[escalated] window.route('${name}') called, but no \`route()\` helper is installed on this host. ` +
|
|
60
|
-
`The escalated agent/admin UI depends on Laravel's Ziggy-style \`route(name, params)\` helper. ` +
|
|
61
|
-
`Install Ziggy (on Laravel hosts) or register a compatible shim on window.route before mounting the app.`,
|
|
62
|
-
);
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const themeDefaults = {
|
|
67
|
-
primary: '#4f46e5',
|
|
68
|
-
primaryHover: null,
|
|
69
|
-
radius: '0.5rem',
|
|
70
|
-
radiusLg: null,
|
|
71
|
-
fontFamily: null,
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
function applyTheme(theme) {
|
|
75
|
-
const merged = { ...themeDefaults, ...theme };
|
|
76
|
-
const style = document.documentElement.style;
|
|
77
|
-
|
|
78
|
-
style.setProperty('--esc-primary', merged.primary);
|
|
79
|
-
style.setProperty('--esc-primary-hover', merged.primaryHover || darken(merged.primary, 10));
|
|
80
|
-
style.setProperty('--esc-radius', merged.radius);
|
|
81
|
-
style.setProperty('--esc-radius-lg', merged.radiusLg || scaleBorderRadius(merged.radius, 1.5));
|
|
82
|
-
|
|
83
|
-
if (merged.fontFamily) {
|
|
84
|
-
style.setProperty('--esc-font-family', merged.fontFamily);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function darken(hex, percent) {
|
|
89
|
-
const num = parseInt(hex.replace('#', ''), 16);
|
|
90
|
-
const r = Math.max(0, (num >> 16) - Math.round(2.55 * percent));
|
|
91
|
-
const g = Math.max(0, ((num >> 8) & 0x00ff) - Math.round(2.55 * percent));
|
|
92
|
-
const b = Math.max(0, (num & 0x0000ff) - Math.round(2.55 * percent));
|
|
93
|
-
return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function scaleBorderRadius(radius, factor) {
|
|
97
|
-
const match = radius.match(/^(\d+(?:\.\d+)?|\.\d+)([a-z%]*)$/i);
|
|
98
|
-
if (!match) return radius;
|
|
99
|
-
return `${(parseFloat(match[1]) * factor).toFixed(2)}${match[2] || 'rem'}`;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const panelDarkDefaults = {
|
|
103
|
-
bg: '#000000',
|
|
104
|
-
sidebarBg: '#0a0a0a',
|
|
105
|
-
topbarBg: 'rgba(0,0,0,0.8)',
|
|
106
|
-
surface: 'rgba(23,23,23,0.6)',
|
|
107
|
-
surfaceAlt: '#0a0a0a',
|
|
108
|
-
border: 'rgba(255,255,255,0.06)',
|
|
109
|
-
borderInput: 'rgba(255,255,255,0.1)',
|
|
110
|
-
text: '#ffffff',
|
|
111
|
-
textSecondary: '#e5e5e5',
|
|
112
|
-
textTertiary: '#a3a3a3',
|
|
113
|
-
textMuted: '#737373',
|
|
114
|
-
accent: '#06b6d4',
|
|
115
|
-
accentSecondary: '#8b5cf6',
|
|
116
|
-
accentHover: '#22d3ee',
|
|
117
|
-
accentSecondaryHover: '#a78bfa',
|
|
118
|
-
hover: 'rgba(255,255,255,0.03)',
|
|
119
|
-
active: 'rgba(255,255,255,0.08)',
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const panelLightDefaults = {
|
|
123
|
-
bg: '#f9fafb',
|
|
124
|
-
sidebarBg: '#ffffff',
|
|
125
|
-
topbarBg: 'rgba(255,255,255,0.95)',
|
|
126
|
-
surface: '#ffffff',
|
|
127
|
-
surfaceAlt: '#f9fafb',
|
|
128
|
-
border: '#e5e7eb',
|
|
129
|
-
borderInput: '#d1d5db',
|
|
130
|
-
text: '#111827',
|
|
131
|
-
textSecondary: '#374151',
|
|
132
|
-
textTertiary: '#6b7280',
|
|
133
|
-
textMuted: '#9ca3af',
|
|
134
|
-
accent: '#3b82f6',
|
|
135
|
-
accentSecondary: '#6366f1',
|
|
136
|
-
accentHover: '#2563eb',
|
|
137
|
-
accentSecondaryHover: '#818cf8',
|
|
138
|
-
hover: 'rgba(0,0,0,0.02)',
|
|
139
|
-
active: '#eff6ff',
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const panelTokenMap = {
|
|
143
|
-
bg: '--esc-panel-bg',
|
|
144
|
-
sidebarBg: '--esc-panel-sidebar-bg',
|
|
145
|
-
topbarBg: '--esc-panel-topbar-bg',
|
|
146
|
-
surface: '--esc-panel-surface',
|
|
147
|
-
surfaceAlt: '--esc-panel-surface-alt',
|
|
148
|
-
border: '--esc-panel-border',
|
|
149
|
-
borderInput: '--esc-panel-border-input',
|
|
150
|
-
text: '--esc-panel-text',
|
|
151
|
-
textSecondary: '--esc-panel-text-secondary',
|
|
152
|
-
textTertiary: '--esc-panel-text-tertiary',
|
|
153
|
-
textMuted: '--esc-panel-text-muted',
|
|
154
|
-
accent: '--esc-panel-accent',
|
|
155
|
-
accentSecondary: '--esc-panel-accent-secondary',
|
|
156
|
-
accentHover: '--esc-panel-accent-hover',
|
|
157
|
-
accentSecondaryHover: '--esc-panel-accent-secondary-hover',
|
|
158
|
-
hover: '--esc-panel-hover',
|
|
159
|
-
active: '--esc-panel-active',
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
function applyPanelTheme(panelConfig) {
|
|
163
|
-
const defaults = panelConfig.mode === 'light' ? panelLightDefaults : panelDarkDefaults;
|
|
164
|
-
const overrides = {};
|
|
165
|
-
for (const key of Object.keys(panelTokenMap)) {
|
|
166
|
-
if (panelConfig[key] !== undefined) {
|
|
167
|
-
overrides[key] = panelConfig[key];
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
const merged = { ...defaults, ...overrides };
|
|
171
|
-
const style = document.documentElement.style;
|
|
172
|
-
for (const [key, cssVar] of Object.entries(panelTokenMap)) {
|
|
173
|
-
style.setProperty(cssVar, merged[key]);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
1
|
+
import { markRaw } from 'vue';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* EscalatedPlugin — Vue plugin for integrating Escalated into your app's design system.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* import { EscalatedPlugin } from '@escalated-dev/escalated'
|
|
8
|
+
* import AppLayout from '@/Layouts/AppLayout.vue'
|
|
9
|
+
*
|
|
10
|
+
* app.use(EscalatedPlugin, {
|
|
11
|
+
* layout: AppLayout,
|
|
12
|
+
* theme: {
|
|
13
|
+
* primary: '#3b82f6',
|
|
14
|
+
* radius: '0.75rem',
|
|
15
|
+
* }
|
|
16
|
+
* })
|
|
17
|
+
*/
|
|
18
|
+
export const EscalatedPlugin = {
|
|
19
|
+
install(app, options = {}) {
|
|
20
|
+
installRouteShim();
|
|
21
|
+
|
|
22
|
+
if (options.layout) {
|
|
23
|
+
app.provide('escalated-layout', markRaw(options.layout));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (options.theme) {
|
|
27
|
+
app.provide('escalated-theme', options.theme);
|
|
28
|
+
applyTheme(options.theme);
|
|
29
|
+
|
|
30
|
+
if (options.theme.panel) {
|
|
31
|
+
const panelConfig = options.theme.panel;
|
|
32
|
+
applyPanelTheme(panelConfig);
|
|
33
|
+
app.provide('escalated-panel', {
|
|
34
|
+
appName: panelConfig.appName || 'Escalated',
|
|
35
|
+
logo: panelConfig.logo || null,
|
|
36
|
+
mode: panelConfig.mode || 'dark',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// 77 components in this package call the Ziggy `route()` helper (Laravel's
|
|
44
|
+
// named-route URL generator). Laravel hosts ship Ziggy and get `window.route`
|
|
45
|
+
// for free; other host frameworks (Rails, Django, NestJS, Phoenix, Symfony,
|
|
46
|
+
// Adonis, Go, .NET, Spring, WordPress) don't, and the call sites would
|
|
47
|
+
// otherwise throw a bare ReferenceError deep inside a component render with
|
|
48
|
+
// no hint at the cause.
|
|
49
|
+
//
|
|
50
|
+
// Install a stub that throws an informative error instead, so the host app's
|
|
51
|
+
// first failing request points at the actual missing dependency. Laravel hosts
|
|
52
|
+
// that already have Ziggy loaded are left alone.
|
|
53
|
+
function installRouteShim() {
|
|
54
|
+
if (typeof window === 'undefined') return;
|
|
55
|
+
if (typeof window.route === 'function') return;
|
|
56
|
+
|
|
57
|
+
window.route = function escalatedRouteShimMissing(name) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`[escalated] window.route('${name}') called, but no \`route()\` helper is installed on this host. ` +
|
|
60
|
+
`The escalated agent/admin UI depends on Laravel's Ziggy-style \`route(name, params)\` helper. ` +
|
|
61
|
+
`Install Ziggy (on Laravel hosts) or register a compatible shim on window.route before mounting the app.`,
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const themeDefaults = {
|
|
67
|
+
primary: '#4f46e5',
|
|
68
|
+
primaryHover: null,
|
|
69
|
+
radius: '0.5rem',
|
|
70
|
+
radiusLg: null,
|
|
71
|
+
fontFamily: null,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
function applyTheme(theme) {
|
|
75
|
+
const merged = { ...themeDefaults, ...theme };
|
|
76
|
+
const style = document.documentElement.style;
|
|
77
|
+
|
|
78
|
+
style.setProperty('--esc-primary', merged.primary);
|
|
79
|
+
style.setProperty('--esc-primary-hover', merged.primaryHover || darken(merged.primary, 10));
|
|
80
|
+
style.setProperty('--esc-radius', merged.radius);
|
|
81
|
+
style.setProperty('--esc-radius-lg', merged.radiusLg || scaleBorderRadius(merged.radius, 1.5));
|
|
82
|
+
|
|
83
|
+
if (merged.fontFamily) {
|
|
84
|
+
style.setProperty('--esc-font-family', merged.fontFamily);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function darken(hex, percent) {
|
|
89
|
+
const num = parseInt(hex.replace('#', ''), 16);
|
|
90
|
+
const r = Math.max(0, (num >> 16) - Math.round(2.55 * percent));
|
|
91
|
+
const g = Math.max(0, ((num >> 8) & 0x00ff) - Math.round(2.55 * percent));
|
|
92
|
+
const b = Math.max(0, (num & 0x0000ff) - Math.round(2.55 * percent));
|
|
93
|
+
return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function scaleBorderRadius(radius, factor) {
|
|
97
|
+
const match = radius.match(/^(\d+(?:\.\d+)?|\.\d+)([a-z%]*)$/i);
|
|
98
|
+
if (!match) return radius;
|
|
99
|
+
return `${(parseFloat(match[1]) * factor).toFixed(2)}${match[2] || 'rem'}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const panelDarkDefaults = {
|
|
103
|
+
bg: '#000000',
|
|
104
|
+
sidebarBg: '#0a0a0a',
|
|
105
|
+
topbarBg: 'rgba(0,0,0,0.8)',
|
|
106
|
+
surface: 'rgba(23,23,23,0.6)',
|
|
107
|
+
surfaceAlt: '#0a0a0a',
|
|
108
|
+
border: 'rgba(255,255,255,0.06)',
|
|
109
|
+
borderInput: 'rgba(255,255,255,0.1)',
|
|
110
|
+
text: '#ffffff',
|
|
111
|
+
textSecondary: '#e5e5e5',
|
|
112
|
+
textTertiary: '#a3a3a3',
|
|
113
|
+
textMuted: '#737373',
|
|
114
|
+
accent: '#06b6d4',
|
|
115
|
+
accentSecondary: '#8b5cf6',
|
|
116
|
+
accentHover: '#22d3ee',
|
|
117
|
+
accentSecondaryHover: '#a78bfa',
|
|
118
|
+
hover: 'rgba(255,255,255,0.03)',
|
|
119
|
+
active: 'rgba(255,255,255,0.08)',
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const panelLightDefaults = {
|
|
123
|
+
bg: '#f9fafb',
|
|
124
|
+
sidebarBg: '#ffffff',
|
|
125
|
+
topbarBg: 'rgba(255,255,255,0.95)',
|
|
126
|
+
surface: '#ffffff',
|
|
127
|
+
surfaceAlt: '#f9fafb',
|
|
128
|
+
border: '#e5e7eb',
|
|
129
|
+
borderInput: '#d1d5db',
|
|
130
|
+
text: '#111827',
|
|
131
|
+
textSecondary: '#374151',
|
|
132
|
+
textTertiary: '#6b7280',
|
|
133
|
+
textMuted: '#9ca3af',
|
|
134
|
+
accent: '#3b82f6',
|
|
135
|
+
accentSecondary: '#6366f1',
|
|
136
|
+
accentHover: '#2563eb',
|
|
137
|
+
accentSecondaryHover: '#818cf8',
|
|
138
|
+
hover: 'rgba(0,0,0,0.02)',
|
|
139
|
+
active: '#eff6ff',
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const panelTokenMap = {
|
|
143
|
+
bg: '--esc-panel-bg',
|
|
144
|
+
sidebarBg: '--esc-panel-sidebar-bg',
|
|
145
|
+
topbarBg: '--esc-panel-topbar-bg',
|
|
146
|
+
surface: '--esc-panel-surface',
|
|
147
|
+
surfaceAlt: '--esc-panel-surface-alt',
|
|
148
|
+
border: '--esc-panel-border',
|
|
149
|
+
borderInput: '--esc-panel-border-input',
|
|
150
|
+
text: '--esc-panel-text',
|
|
151
|
+
textSecondary: '--esc-panel-text-secondary',
|
|
152
|
+
textTertiary: '--esc-panel-text-tertiary',
|
|
153
|
+
textMuted: '--esc-panel-text-muted',
|
|
154
|
+
accent: '--esc-panel-accent',
|
|
155
|
+
accentSecondary: '--esc-panel-accent-secondary',
|
|
156
|
+
accentHover: '--esc-panel-accent-hover',
|
|
157
|
+
accentSecondaryHover: '--esc-panel-accent-secondary-hover',
|
|
158
|
+
hover: '--esc-panel-hover',
|
|
159
|
+
active: '--esc-panel-active',
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
function applyPanelTheme(panelConfig) {
|
|
163
|
+
const defaults = panelConfig.mode === 'light' ? panelLightDefaults : panelDarkDefaults;
|
|
164
|
+
const overrides = {};
|
|
165
|
+
for (const key of Object.keys(panelTokenMap)) {
|
|
166
|
+
if (panelConfig[key] !== undefined) {
|
|
167
|
+
overrides[key] = panelConfig[key];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const merged = { ...defaults, ...overrides };
|
|
171
|
+
const style = document.documentElement.style;
|
|
172
|
+
for (const [key, cssVar] of Object.entries(panelTokenMap)) {
|
|
173
|
+
style.setProperty(cssVar, merged[key]);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTML-encode a string to prevent injection via mention names.
|
|
3
|
-
*/
|
|
4
|
-
function escapeHtml(str) {
|
|
5
|
-
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Replace @{Name} patterns in text with styled mention badges.
|
|
10
|
-
*
|
|
11
|
-
* @param {string} html - The HTML or text content
|
|
12
|
-
* @param {boolean} dark - Whether dark mode is active
|
|
13
|
-
* @returns {string} HTML with mentions wrapped in styled spans
|
|
14
|
-
*/
|
|
15
|
-
export function highlightMentions(html, dark = false) {
|
|
16
|
-
if (!html) return '';
|
|
17
|
-
|
|
18
|
-
const pillClass = dark
|
|
19
|
-
? 'inline-flex items-center rounded-full bg-cyan-500/15 px-1.5 py-0.5 text-xs font-medium text-cyan-400 ring-1 ring-cyan-500/20'
|
|
20
|
-
: 'inline-flex items-center rounded-full bg-blue-100 px-1.5 py-0.5 text-xs font-medium text-blue-700 ring-1 ring-blue-200';
|
|
21
|
-
|
|
22
|
-
// Replace @{Name} with styled pill, encoding the name to prevent injection
|
|
23
|
-
return html.replace(/@\{([^}]+)\}/g, (match, name) => `<span class="${pillClass}">@${escapeHtml(name)}</span>`);
|
|
24
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* HTML-encode a string to prevent injection via mention names.
|
|
3
|
+
*/
|
|
4
|
+
function escapeHtml(str) {
|
|
5
|
+
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Replace @{Name} patterns in text with styled mention badges.
|
|
10
|
+
*
|
|
11
|
+
* @param {string} html - The HTML or text content
|
|
12
|
+
* @param {boolean} dark - Whether dark mode is active
|
|
13
|
+
* @returns {string} HTML with mentions wrapped in styled spans
|
|
14
|
+
*/
|
|
15
|
+
export function highlightMentions(html, dark = false) {
|
|
16
|
+
if (!html) return '';
|
|
17
|
+
|
|
18
|
+
const pillClass = dark
|
|
19
|
+
? 'inline-flex items-center rounded-full bg-cyan-500/15 px-1.5 py-0.5 text-xs font-medium text-cyan-400 ring-1 ring-cyan-500/20'
|
|
20
|
+
: 'inline-flex items-center rounded-full bg-blue-100 px-1.5 py-0.5 text-xs font-medium text-blue-700 ring-1 ring-blue-200';
|
|
21
|
+
|
|
22
|
+
// Replace @{Name} with styled pill, encoding the name to prevent injection
|
|
23
|
+
return html.replace(/@\{([^}]+)\}/g, (match, name) => `<span class="${pillClass}">@${escapeHtml(name)}</span>`);
|
|
24
|
+
}
|