mgv-backoffice 1.36.3 → 1.38.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/README.md +120 -3
- package/dist/components/BaseCard.vue.d.ts +33 -0
- package/dist/components/BaseDateTimePicker.vue.d.ts +49 -0
- package/dist/components/BaseField.vue.d.ts +38 -0
- package/dist/components/BaseSearchSelect.vue.d.ts +41 -0
- package/dist/components/BaseStatCard.vue.d.ts +33 -0
- package/dist/components/BaseTable.vue.d.ts +3 -0
- package/dist/index.d.ts +6 -0
- package/dist/ui-lib.css +1 -1
- package/dist/ui-lib.js +1308 -911
- package/dist/ui-lib.umd.cjs +1 -1
- package/package.json +4 -1
- package/src/components/BaseBreadcrumb.vue +68 -68
- package/src/components/BaseCard.test.ts +55 -0
- package/src/components/BaseCard.vue +48 -0
- package/src/components/BaseDateTimePicker.test.ts +49 -0
- package/src/components/BaseDateTimePicker.vue +91 -0
- package/src/components/BaseField.vue +47 -0
- package/src/components/BaseInput.test.ts +1 -1
- package/src/components/BaseInput.vue +46 -46
- package/src/components/BaseLogo.test.ts +26 -0
- package/src/components/BaseLogo.vue +7 -1
- package/src/components/BaseSearchSelect.test.ts +117 -0
- package/src/components/BaseSearchSelect.vue +318 -0
- package/src/components/BaseSelect.test.ts +3 -3
- package/src/components/BaseSelect.vue +61 -46
- package/src/components/BaseStatCard.test.ts +40 -0
- package/src/components/BaseStatCard.vue +103 -0
- package/src/components/BaseTable.test.ts +69 -55
- package/src/components/BaseTable.vue +62 -50
- package/src/index.ts +8 -0
- package/src/style.css +58 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:is="to ? RouterLink : 'div'"
|
|
4
|
+
v-bind="to ? { to } : {}"
|
|
5
|
+
class="relative block rounded-xl border-2 border-dashed bg-white p-5 transition-colors dark:bg-slate-800"
|
|
6
|
+
:class="[cls.border, to ? 'hover:bg-slate-50 dark:hover:bg-slate-700/60 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500' : '']"
|
|
7
|
+
>
|
|
8
|
+
<div class="flex items-start justify-between gap-3">
|
|
9
|
+
<div class="min-w-0 text-left">
|
|
10
|
+
<p class="truncate text-sm font-bold tracking-wide text-gray-800 dark:text-slate-200">
|
|
11
|
+
{{ title }}
|
|
12
|
+
</p>
|
|
13
|
+
<p class="mt-1 truncate text-3xl font-bold" :class="cls.value">
|
|
14
|
+
{{ value }}
|
|
15
|
+
</p>
|
|
16
|
+
<p v-if="subtitle" class="mt-1 text-sm font-medium" :class="cls.subtitle">
|
|
17
|
+
{{ subtitle }}
|
|
18
|
+
</p>
|
|
19
|
+
<slot />
|
|
20
|
+
</div>
|
|
21
|
+
<div
|
|
22
|
+
v-if="$slots.icon"
|
|
23
|
+
class="flex h-12 w-12 shrink-0 items-center justify-center rounded-xl"
|
|
24
|
+
:class="cls.iconBox"
|
|
25
|
+
>
|
|
26
|
+
<slot name="icon" :icon-class="`h-6 w-6 ${cls.icon}`" />
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</component>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup lang="ts">
|
|
33
|
+
/**
|
|
34
|
+
* Dashboard stat tile in the EarningsCard style (dashed accent border,
|
|
35
|
+
* bold title, big value, accent subtitle, tinted icon chip) but for any
|
|
36
|
+
* value — counts, labels, pre-formatted numbers. Pass `to` to make the whole
|
|
37
|
+
* card a router link. The `icon` slot fills the chip (receives `iconClass`);
|
|
38
|
+
* the `default` slot adds extra content under the subtitle.
|
|
39
|
+
*
|
|
40
|
+
*/
|
|
41
|
+
import { computed } from 'vue'
|
|
42
|
+
import { RouterLink, type RouteLocationRaw } from 'vue-router'
|
|
43
|
+
|
|
44
|
+
type Accent = 'emerald' | 'sky' | 'amber' | 'red' | 'slate'
|
|
45
|
+
|
|
46
|
+
interface Props {
|
|
47
|
+
title: string
|
|
48
|
+
value?: string | number
|
|
49
|
+
subtitle?: string
|
|
50
|
+
/** Border / value / subtitle / icon tint. */
|
|
51
|
+
accent?: Accent
|
|
52
|
+
/** Makes the card a router link. */
|
|
53
|
+
to?: RouteLocationRaw
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
57
|
+
value: '',
|
|
58
|
+
subtitle: '',
|
|
59
|
+
accent: 'emerald',
|
|
60
|
+
to: undefined,
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// Full literal class strings per accent so Tailwind can see every class.
|
|
64
|
+
const ACCENTS: Record<Accent, { border: string; value: string; subtitle: string; iconBox: string; icon: string }> = {
|
|
65
|
+
emerald: {
|
|
66
|
+
border: 'border-emerald-300 dark:border-emerald-700',
|
|
67
|
+
value: 'text-emerald-500 dark:text-emerald-400',
|
|
68
|
+
subtitle: 'text-emerald-500 dark:text-emerald-400',
|
|
69
|
+
iconBox: 'bg-emerald-50 dark:bg-emerald-900/30',
|
|
70
|
+
icon: 'text-emerald-500',
|
|
71
|
+
},
|
|
72
|
+
sky: {
|
|
73
|
+
border: 'border-sky-300 dark:border-sky-700',
|
|
74
|
+
value: 'text-sky-500 dark:text-sky-400',
|
|
75
|
+
subtitle: 'text-sky-500 dark:text-sky-400',
|
|
76
|
+
iconBox: 'bg-sky-50 dark:bg-sky-900/30',
|
|
77
|
+
icon: 'text-sky-500',
|
|
78
|
+
},
|
|
79
|
+
amber: {
|
|
80
|
+
border: 'border-amber-300 dark:border-amber-700',
|
|
81
|
+
value: 'text-amber-500 dark:text-amber-400',
|
|
82
|
+
subtitle: 'text-amber-500 dark:text-amber-400',
|
|
83
|
+
iconBox: 'bg-amber-50 dark:bg-amber-900/30',
|
|
84
|
+
icon: 'text-amber-500',
|
|
85
|
+
},
|
|
86
|
+
red: {
|
|
87
|
+
border: 'border-red-300 dark:border-red-700',
|
|
88
|
+
value: 'text-red-500 dark:text-red-400',
|
|
89
|
+
subtitle: 'text-red-500 dark:text-red-400',
|
|
90
|
+
iconBox: 'bg-red-50 dark:bg-red-900/30',
|
|
91
|
+
icon: 'text-red-500',
|
|
92
|
+
},
|
|
93
|
+
slate: {
|
|
94
|
+
border: 'border-slate-300 dark:border-slate-600',
|
|
95
|
+
value: 'text-slate-700 dark:text-slate-200',
|
|
96
|
+
subtitle: 'text-slate-500 dark:text-slate-400',
|
|
97
|
+
iconBox: 'bg-slate-100 dark:bg-slate-700/50',
|
|
98
|
+
icon: 'text-slate-500 dark:text-slate-300',
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const cls = computed(() => ACCENTS[props.accent])
|
|
103
|
+
</script>
|
|
@@ -1,55 +1,69 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { mount } from '@vue/test-utils'
|
|
3
|
-
import BaseTable from './BaseTable.vue'
|
|
4
|
-
import type { TableColumn } from '../types/table'
|
|
5
|
-
|
|
6
|
-
const columns: TableColumn[] = [
|
|
7
|
-
{ label: 'Symbol' },
|
|
8
|
-
{ label: 'Qty', align: 'right' },
|
|
9
|
-
{ label: 'Bought' },
|
|
10
|
-
]
|
|
11
|
-
|
|
12
|
-
describe('BaseTable', () => {
|
|
13
|
-
it('renders header cells with right-alignment where requested', () => {
|
|
14
|
-
const wrapper = mount(BaseTable, { props: { columns } })
|
|
15
|
-
const ths = wrapper.findAll('th')
|
|
16
|
-
expect(ths.map((th) => th.text())).toEqual(['Symbol', 'Qty', 'Bought'])
|
|
17
|
-
expect(ths[1].classes()).toContain('text-right')
|
|
18
|
-
expect(ths[0].classes()).not.toContain('text-right')
|
|
19
|
-
expect(ths[0].classes()).toEqual(expect.arrayContaining(['px-4', 'py-3']))
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
it('renders caller rows through the default slot', () => {
|
|
23
|
-
const wrapper = mount(BaseTable, {
|
|
24
|
-
props: { columns },
|
|
25
|
-
slots: { default: '<tr><td>AMD</td><td>3</td><td>today</td></tr>' },
|
|
26
|
-
})
|
|
27
|
-
expect(wrapper.find('tbody td').text()).toBe('AMD')
|
|
28
|
-
expect(wrapper.find('table').classes()).toEqual(expect.arrayContaining(['w-full', 'text-sm']))
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('renders the empty-state row spanning every column when empty', () => {
|
|
32
|
-
const wrapper = mount(BaseTable, {
|
|
33
|
-
props: { columns, empty: true, emptyText: 'Nothing here.' },
|
|
34
|
-
})
|
|
35
|
-
const td = wrapper.find('tbody td')
|
|
36
|
-
expect(td.attributes('colspan')).toBe('3')
|
|
37
|
-
expect(td.text()).toBe('Nothing here.')
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('prefers the empty slot over emptyText', () => {
|
|
41
|
-
const wrapper = mount(BaseTable, {
|
|
42
|
-
props: { columns, empty: true, emptyText: 'fallback' },
|
|
43
|
-
slots: { empty: 'No trades match your filters.' },
|
|
44
|
-
})
|
|
45
|
-
expect(wrapper.find('tbody td').text()).toBe('No trades match your filters.')
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('renders no empty-state row when not empty', () => {
|
|
49
|
-
const wrapper = mount(BaseTable, {
|
|
50
|
-
props: { columns, empty: false },
|
|
51
|
-
slots: { default: '<tr><td>row</td></tr>' },
|
|
52
|
-
})
|
|
53
|
-
expect(wrapper.findAll('tbody tr')).toHaveLength(1)
|
|
54
|
-
})
|
|
55
|
-
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import BaseTable from './BaseTable.vue'
|
|
4
|
+
import type { TableColumn } from '../types/table'
|
|
5
|
+
|
|
6
|
+
const columns: TableColumn[] = [
|
|
7
|
+
{ label: 'Symbol' },
|
|
8
|
+
{ label: 'Qty', align: 'right' },
|
|
9
|
+
{ label: 'Bought' },
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
describe('BaseTable', () => {
|
|
13
|
+
it('renders header cells with right-alignment where requested', () => {
|
|
14
|
+
const wrapper = mount(BaseTable, { props: { columns } })
|
|
15
|
+
const ths = wrapper.findAll('th')
|
|
16
|
+
expect(ths.map((th) => th.text())).toEqual(['Symbol', 'Qty', 'Bought'])
|
|
17
|
+
expect(ths[1].classes()).toContain('text-right')
|
|
18
|
+
expect(ths[0].classes()).not.toContain('text-right')
|
|
19
|
+
expect(ths[0].classes()).toEqual(expect.arrayContaining(['px-4', 'py-3']))
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('renders caller rows through the default slot', () => {
|
|
23
|
+
const wrapper = mount(BaseTable, {
|
|
24
|
+
props: { columns },
|
|
25
|
+
slots: { default: '<tr><td>AMD</td><td>3</td><td>today</td></tr>' },
|
|
26
|
+
})
|
|
27
|
+
expect(wrapper.find('tbody td').text()).toBe('AMD')
|
|
28
|
+
expect(wrapper.find('table').classes()).toEqual(expect.arrayContaining(['w-full', 'text-sm']))
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('renders the empty-state row spanning every column when empty', () => {
|
|
32
|
+
const wrapper = mount(BaseTable, {
|
|
33
|
+
props: { columns, empty: true, emptyText: 'Nothing here.' },
|
|
34
|
+
})
|
|
35
|
+
const td = wrapper.find('tbody td')
|
|
36
|
+
expect(td.attributes('colspan')).toBe('3')
|
|
37
|
+
expect(td.text()).toBe('Nothing here.')
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('prefers the empty slot over emptyText', () => {
|
|
41
|
+
const wrapper = mount(BaseTable, {
|
|
42
|
+
props: { columns, empty: true, emptyText: 'fallback' },
|
|
43
|
+
slots: { empty: 'No trades match your filters.' },
|
|
44
|
+
})
|
|
45
|
+
expect(wrapper.find('tbody td').text()).toBe('No trades match your filters.')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('renders no empty-state row when not empty', () => {
|
|
49
|
+
const wrapper = mount(BaseTable, {
|
|
50
|
+
props: { columns, empty: false },
|
|
51
|
+
slots: { default: '<tr><td>row</td></tr>' },
|
|
52
|
+
})
|
|
53
|
+
expect(wrapper.findAll('tbody tr')).toHaveLength(1)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('has no card chrome by default and adds it with `card`', () => {
|
|
57
|
+
const plain = mount(BaseTable, { props: { columns } })
|
|
58
|
+
expect(plain.classes()).not.toContain('border')
|
|
59
|
+
const card = mount(BaseTable, { props: { columns, card: true } })
|
|
60
|
+
expect(card.classes()).toEqual(
|
|
61
|
+
expect.arrayContaining(['overflow-x-auto', 'rounded-xl', 'border']),
|
|
62
|
+
)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('draws row dividers on the body', () => {
|
|
66
|
+
const wrapper = mount(BaseTable, { props: { columns } })
|
|
67
|
+
expect(wrapper.find('tbody').classes()).toEqual(expect.arrayContaining(['divide-y']))
|
|
68
|
+
})
|
|
69
|
+
})
|
|
@@ -1,50 +1,62 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
</
|
|
34
|
-
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="card ? CARD_CLASS : undefined">
|
|
3
|
+
<!--
|
|
4
|
+
Styling shell for data tables — NOT a data grid. Owns the table skin
|
|
5
|
+
(slate header band, px-4 py-3 header cells, row dividers + hover,
|
|
6
|
+
empty-state row); rows are the caller's own <tr> markup via the default
|
|
7
|
+
slot, so cell content and per-cell styling stay fully in the caller's hands.
|
|
8
|
+
|
|
9
|
+
`card` adds the shared card chrome (rounded border, surface, horizontal
|
|
10
|
+
scroll). Leave it off when the caller already wraps the table itself
|
|
11
|
+
(e.g. inside a BaseRow with overflow-x-auto). Same `dark:`-variant note
|
|
12
|
+
as BaseInput.
|
|
13
|
+
-->
|
|
14
|
+
<table class="w-full text-sm">
|
|
15
|
+
<thead class="bg-slate-50 dark:bg-slate-800/60 text-slate-600 dark:text-slate-300">
|
|
16
|
+
<tr class="text-left border-b border-slate-200 dark:border-slate-700">
|
|
17
|
+
<th
|
|
18
|
+
v-for="(col, i) in columns"
|
|
19
|
+
:key="i"
|
|
20
|
+
class="px-4 py-3"
|
|
21
|
+
:class="col.align === 'right' ? 'text-right' : ''"
|
|
22
|
+
>
|
|
23
|
+
{{ col.label }}
|
|
24
|
+
</th>
|
|
25
|
+
</tr>
|
|
26
|
+
</thead>
|
|
27
|
+
<tbody
|
|
28
|
+
class="divide-y divide-slate-200 dark:divide-slate-700 [&>tr]:transition-colors [&>tr:hover]:bg-slate-50 dark:[&>tr:hover]:bg-slate-800/40"
|
|
29
|
+
>
|
|
30
|
+
<tr v-if="empty">
|
|
31
|
+
<td :colspan="columns.length" class="px-4 py-12 text-center text-slate-500">
|
|
32
|
+
<slot name="empty">{{ emptyText }}</slot>
|
|
33
|
+
</td>
|
|
34
|
+
</tr>
|
|
35
|
+
<slot />
|
|
36
|
+
</tbody>
|
|
37
|
+
</table>
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
40
|
+
|
|
41
|
+
<script setup lang="ts">
|
|
42
|
+
import type { TableColumn } from '../types/table'
|
|
43
|
+
|
|
44
|
+
const CARD_CLASS =
|
|
45
|
+
'overflow-x-auto rounded-xl border border-slate-200 bg-white shadow-sm dark:border-slate-700 dark:bg-slate-900'
|
|
46
|
+
|
|
47
|
+
interface Props {
|
|
48
|
+
columns: TableColumn[]
|
|
49
|
+
/** True when there are no rows — renders the empty-state row. */
|
|
50
|
+
empty?: boolean
|
|
51
|
+
/** Fallback empty-state text; the `empty` slot overrides it. */
|
|
52
|
+
emptyText?: string
|
|
53
|
+
/** Wrap the table in the rounded, bordered, horizontally scrolling card. */
|
|
54
|
+
card?: boolean
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
withDefaults(defineProps<Props>(), {
|
|
58
|
+
empty: false,
|
|
59
|
+
emptyText: 'No rows.',
|
|
60
|
+
card: false,
|
|
61
|
+
})
|
|
62
|
+
</script>
|
package/src/index.ts
CHANGED
|
@@ -53,6 +53,14 @@ export { default as BasePillPickerModal } from './components/BasePillPickerModal
|
|
|
53
53
|
export { default as BaseBarDistribution } from './components/BaseBarDistribution.vue'
|
|
54
54
|
export type { CredentialsView, CredentialsUpdate } from './components/BaseCredentialsForm.vue'
|
|
55
55
|
|
|
56
|
+
// Components — third-party wrappers
|
|
57
|
+
export { default as BaseDateTimePicker } from './components/BaseDateTimePicker.vue'
|
|
58
|
+
export type { DateTimePickerMode } from './components/BaseDateTimePicker.vue'
|
|
59
|
+
export { default as BaseSearchSelect } from './components/BaseSearchSelect.vue'
|
|
60
|
+
export { default as BaseCard } from './components/BaseCard.vue'
|
|
61
|
+
export { default as BaseField } from './components/BaseField.vue'
|
|
62
|
+
export { default as BaseStatCard } from './components/BaseStatCard.vue'
|
|
63
|
+
|
|
56
64
|
// Composables
|
|
57
65
|
export { useTheme, initTheme } from './composables/useTheme'
|
|
58
66
|
export type { UseThemeOptions } from './composables/useTheme'
|
package/src/style.css
CHANGED
|
@@ -30,3 +30,61 @@
|
|
|
30
30
|
body {
|
|
31
31
|
font-family: var(--font-sans);
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
/* BaseDateTimePicker skin: re-point @vuepic/vue-datepicker's CSS variables at
|
|
35
|
+
the lib palette (emerald accent, slate surfaces — same as BaseInput). The
|
|
36
|
+
picker is third-party markup, so its variables are the only styling hook;
|
|
37
|
+
Tailwind utilities can't reach inside it. `html` prefix out-specifies the
|
|
38
|
+
package's own `.dp--theme-*` blocks regardless of stylesheet order. */
|
|
39
|
+
html .dp--theme-light,
|
|
40
|
+
html .dp--theme-dark {
|
|
41
|
+
--dp-font-family: var(--font-sans);
|
|
42
|
+
--dp-font-size: 0.875rem;
|
|
43
|
+
--dp-border-radius: 0.25rem;
|
|
44
|
+
--dp-cell-border-radius: 0.25rem;
|
|
45
|
+
--dp-input-padding: 8px 30px 8px 12px;
|
|
46
|
+
--dp-primary-text-color: #fff;
|
|
47
|
+
}
|
|
48
|
+
html .dp--theme-light {
|
|
49
|
+
--dp-background-color: #f8fafc; /* slate-50 */
|
|
50
|
+
--dp-text-color: #0f172a; /* slate-900 */
|
|
51
|
+
--dp-hover-color: #f1f5f9; /* slate-100 */
|
|
52
|
+
--dp-hover-text-color: #0f172a;
|
|
53
|
+
--dp-hover-icon-color: #64748b; /* slate-500 */
|
|
54
|
+
--dp-icon-color: #94a3b8; /* slate-400 */
|
|
55
|
+
--dp-primary-color: #059669; /* emerald-600 */
|
|
56
|
+
--dp-primary-disabled-color: #6ee7b7; /* emerald-300 */
|
|
57
|
+
--dp-secondary-color: #94a3b8;
|
|
58
|
+
--dp-border-color: #cbd5e1; /* slate-300 */
|
|
59
|
+
--dp-menu-border-color: #cbd5e1;
|
|
60
|
+
--dp-border-color-hover: #94a3b8;
|
|
61
|
+
--dp-border-color-focus: #10b981; /* emerald-500 */
|
|
62
|
+
--dp-highlight-color: rgb(16 185 129 / 0.12);
|
|
63
|
+
--dp-success-color: #10b981;
|
|
64
|
+
--dp-danger-color: #ef4444; /* red-500 */
|
|
65
|
+
--dp-marker-color: #ef4444;
|
|
66
|
+
}
|
|
67
|
+
html .dp--theme-dark {
|
|
68
|
+
--dp-background-color: #0f172a; /* slate-900 */
|
|
69
|
+
--dp-text-color: #f1f5f9; /* slate-100 */
|
|
70
|
+
--dp-hover-color: #1e293b; /* slate-800 */
|
|
71
|
+
--dp-hover-text-color: #f1f5f9;
|
|
72
|
+
--dp-hover-icon-color: #cbd5e1; /* slate-300 */
|
|
73
|
+
--dp-icon-color: #64748b; /* slate-500 */
|
|
74
|
+
--dp-primary-color: #059669; /* emerald-600 */
|
|
75
|
+
--dp-primary-disabled-color: #065f46; /* emerald-800 */
|
|
76
|
+
--dp-secondary-color: #64748b;
|
|
77
|
+
--dp-border-color: #475569; /* slate-600 */
|
|
78
|
+
--dp-menu-border-color: #334155; /* slate-700 */
|
|
79
|
+
--dp-border-color-hover: #64748b;
|
|
80
|
+
--dp-border-color-focus: #10b981; /* emerald-500 */
|
|
81
|
+
--dp-highlight-color: rgb(16 185 129 / 0.2);
|
|
82
|
+
--dp-disabled-color: #1e293b;
|
|
83
|
+
--dp-disabled-color-text: #64748b;
|
|
84
|
+
--dp-scroll-bar-background: #0f172a;
|
|
85
|
+
--dp-scroll-bar-color: #334155;
|
|
86
|
+
--dp-success-color: #10b981;
|
|
87
|
+
--dp-danger-color: #ef4444;
|
|
88
|
+
--dp-marker-color: #ef4444;
|
|
89
|
+
--dp-tooltip-color: #1e293b;
|
|
90
|
+
}
|