@morscherlab/mint-sdk 1.4.5 → 1.4.7
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/{AppSidebar-BI5r4vg1.js → AppSidebar-B3JVHxwN.js} +3 -3
- package/dist/{AppSidebar-BI5r4vg1.js.map → AppSidebar-B3JVHxwN.js.map} +1 -1
- package/dist/{SettingsModal-dC0TCvPr.js → SettingsModal-COQ2krOp.js} +4 -4
- package/dist/{SettingsModal-dC0TCvPr.js.map → SettingsModal-COQ2krOp.js.map} +1 -1
- package/dist/components/SectionCard.vue.d.ts +13 -1
- package/dist/{controlSchemaModel-BbXbMgc6.js → controlSchemaModel-C20f-1_T.js} +2 -2
- package/dist/{controlSchemaModel-BbXbMgc6.js.map → controlSchemaModel-C20f-1_T.js.map} +1 -1
- package/dist/index.js +9 -9
- package/dist/{install-r_GzERvy.js → install-B2XlrT-x.js} +8 -8
- package/dist/{install-r_GzERvy.js.map → install-B2XlrT-x.js.map} +1 -1
- package/dist/install.js +1 -1
- package/dist/{lab-CbdDLAVr.js → lab-B5sKmlWF.js} +75 -24
- package/dist/lab-B5sKmlWF.js.map +1 -0
- package/dist/lab.js +3 -3
- package/dist/{runtime-D77Lk7Pk.js → runtime-CCfoAQcC.js} +5 -5
- package/dist/{runtime-D77Lk7Pk.js.map → runtime-CCfoAQcC.js.map} +1 -1
- package/dist/runtime.js +4 -4
- package/dist/{shell-Bqb2_v3D.js → shell-Chc-muxT.js} +3 -3
- package/dist/{shell-Bqb2_v3D.js.map → shell-Chc-muxT.js.map} +1 -1
- package/dist/shell.js +3 -3
- package/dist/styles.css +78 -15
- package/dist/styles.d.ts +1 -0
- package/dist/{useListReorder-QqJc1dpX.js → useListReorder-C--K06el.js} +14 -2
- package/dist/useListReorder-C--K06el.js.map +1 -0
- package/dist/{useRackEditor-BHGM1Ngz.js → useRackEditor-Cba_0OfI.js} +2 -2
- package/dist/{useRackEditor-BHGM1Ngz.js.map → useRackEditor-Cba_0OfI.js.map} +1 -1
- package/package.json +5 -2
- package/src/__tests__/components/SectionCard.test.ts +33 -0
- package/src/__tests__/composables/useJobsEndpoint.test.ts +50 -0
- package/src/components/InstrumentStatusPanels.vue +3 -3
- package/src/components/SectionCard.vue +42 -6
- package/src/composables/useJobsEndpoint.ts +15 -4
- package/src/styles/components/section-card.css +65 -6
- package/src/styles/variables.css +4 -0
- package/dist/lab-CbdDLAVr.js.map +0 -1
- package/dist/useListReorder-QqJc1dpX.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morscherlab/mint-sdk",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.7",
|
|
4
4
|
"description": "MINT Platform SDK — Vue 3 components, composables, and types for plugin development. MINT = Mass-spec Infrastructure for Next-generation Toolkits.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -51,7 +51,10 @@
|
|
|
51
51
|
"types": "./dist/types/index.d.ts",
|
|
52
52
|
"import": "./dist/types/index.js"
|
|
53
53
|
},
|
|
54
|
-
"./styles":
|
|
54
|
+
"./styles": {
|
|
55
|
+
"types": "./dist/styles.d.ts",
|
|
56
|
+
"default": "./dist/styles.css"
|
|
57
|
+
}
|
|
55
58
|
},
|
|
56
59
|
"files": [
|
|
57
60
|
"dist",
|
|
@@ -178,4 +178,37 @@ describe('SectionCard', () => {
|
|
|
178
178
|
expect(withoutFooter.find('.mint-section-card__footer').exists()).toBe(false)
|
|
179
179
|
})
|
|
180
180
|
})
|
|
181
|
+
|
|
182
|
+
describe('collapsible', () => {
|
|
183
|
+
it('should hide the body and emit the collapsed state when a collapsible header is clicked', async () => {
|
|
184
|
+
const wrapper = mount(SectionCard, {
|
|
185
|
+
props: { title: 'Alerts', count: 3, collapsible: true },
|
|
186
|
+
slots: { default: '<p class="body-probe">rows</p>', actions: '<button class="action-probe">Export</button>' },
|
|
187
|
+
attachTo: document.body,
|
|
188
|
+
})
|
|
189
|
+
const toggle = wrapper.find('button.mint-section-card__toggle')
|
|
190
|
+
expect(toggle.attributes('aria-expanded')).toBe('true')
|
|
191
|
+
expect(wrapper.find('h2.mint-section-card__title > button').element).toBe(toggle.element)
|
|
192
|
+
expect(toggle.text()).toContain('Alerts')
|
|
193
|
+
expect(toggle.find('.action-probe').exists()).toBe(false)
|
|
194
|
+
|
|
195
|
+
await toggle.trigger('click')
|
|
196
|
+
|
|
197
|
+
expect(toggle.attributes('aria-expanded')).toBe('false')
|
|
198
|
+
expect(wrapper.find('.mint-section-card__body').isVisible()).toBe(false)
|
|
199
|
+
expect(wrapper.emitted('update:collapsed')).toEqual([[true]])
|
|
200
|
+
wrapper.unmount()
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it('should keep the body visible with no toggle when collapsed is set without collapsible', () => {
|
|
204
|
+
const wrapper = mount(SectionCard, {
|
|
205
|
+
props: { title: 'Alerts', collapsed: true },
|
|
206
|
+
slots: { default: '<p class="body-probe">rows</p>' },
|
|
207
|
+
attachTo: document.body,
|
|
208
|
+
})
|
|
209
|
+
expect(wrapper.find('.mint-section-card__toggle').exists()).toBe(false)
|
|
210
|
+
expect(wrapper.find('.mint-section-card__body').isVisible()).toBe(true)
|
|
211
|
+
wrapper.unmount()
|
|
212
|
+
})
|
|
213
|
+
})
|
|
181
214
|
})
|
|
@@ -1595,6 +1595,56 @@ describe('useJobsEndpoint', () => {
|
|
|
1595
1595
|
}
|
|
1596
1596
|
})
|
|
1597
1597
|
|
|
1598
|
+
it.each([
|
|
1599
|
+
{ name: 'resolves when the server still has the job', answers: [() => response(completedJob('submitted-job'))], outcome: 'completed' },
|
|
1600
|
+
{ name: 'rejects when the server no longer has the job', answers: [() => response({ detail: 'Job not found' }, 404)], outcome: 'Job submitted-job is no longer available' },
|
|
1601
|
+
{ name: 'checks again on the next snapshot after a retryable error', answers: [() => response({ detail: 'Busy' }, 503), () => response(completedJob('submitted-job'))], outcome: 'completed' },
|
|
1602
|
+
])('should check a waited job that a stale stream snapshot omits and $name', async ({ answers, outcome }) => {
|
|
1603
|
+
const encoder = new TextEncoder()
|
|
1604
|
+
let pushFrame!: (frame: string) => void
|
|
1605
|
+
const stream = new ReadableStream<Uint8Array>({
|
|
1606
|
+
start(controller) { pushFrame = frame => controller.enqueue(encoder.encode(frame)) },
|
|
1607
|
+
})
|
|
1608
|
+
let lookups = 0
|
|
1609
|
+
const transport = vi.fn<GeneratedAnalysisTransport>(async (input, init) => {
|
|
1610
|
+
const url = String(input)
|
|
1611
|
+
if (url.endsWith('/jobs/sessions') && init?.method === 'GET') return response({ sessions: [] })
|
|
1612
|
+
if (url.endsWith('/jobs/sessions')) {
|
|
1613
|
+
return response({ id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [] })
|
|
1614
|
+
}
|
|
1615
|
+
if (url.endsWith('/jobs/events')) return new Response(stream, { headers: { 'Content-Type': 'text/event-stream' } })
|
|
1616
|
+
if (url.endsWith('/jobs') && init?.method === 'POST') return response(activeJob('submitted-job'))
|
|
1617
|
+
if (url.endsWith('/jobs')) return response({ jobs: [] })
|
|
1618
|
+
if (url.endsWith('/jobs/submitted-job')) {
|
|
1619
|
+
lookups += 1
|
|
1620
|
+
return lookups === 1 ? response(activeJob('submitted-job', 'running')) : answers[lookups - 2]!()
|
|
1621
|
+
}
|
|
1622
|
+
throw new Error(`Unexpected request: ${url}`)
|
|
1623
|
+
})
|
|
1624
|
+
const scope = effectScope()
|
|
1625
|
+
const generated = scope.run(() => useJobsEndpoint({
|
|
1626
|
+
baseUrl: '/api/demo',
|
|
1627
|
+
transport,
|
|
1628
|
+
storage: memoryStorage(),
|
|
1629
|
+
createId: () => 'tab-1',
|
|
1630
|
+
streamReconnectDelay: 60_000,
|
|
1631
|
+
}))!
|
|
1632
|
+
|
|
1633
|
+
try {
|
|
1634
|
+
const waiting = generated.wait(await generated.submit('run', {}))
|
|
1635
|
+
.then(job => job.status, (cause: Error) => cause.message)
|
|
1636
|
+
// Each snapshot was built before the submit reached the server.
|
|
1637
|
+
for (const [index] of answers.entries()) {
|
|
1638
|
+
await vi.waitFor(() => expect(lookups).toBe(index + 1))
|
|
1639
|
+
pushFrame(`event: snapshot\ndata: ${JSON.stringify({ jobs: [] })}\n\n`)
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
expect(await waiting).toBe(outcome)
|
|
1643
|
+
} finally {
|
|
1644
|
+
scope.stop()
|
|
1645
|
+
}
|
|
1646
|
+
})
|
|
1647
|
+
|
|
1598
1648
|
it('rejects pending waiters when their job is deleted or the runtime is disposed', async () => {
|
|
1599
1649
|
const queued = activeJob('delete-wait-job')
|
|
1600
1650
|
const disposeJobRequest = deferred<Response>()
|
|
@@ -105,11 +105,11 @@ function formatValue(value: string | number | boolean | null): string {
|
|
|
105
105
|
</template>
|
|
106
106
|
|
|
107
107
|
<style scoped>
|
|
108
|
-
.mint-status-panels__tabs { padding: 0
|
|
109
|
-
.mint-status-panels__body { padding: 0.75rem
|
|
108
|
+
.mint-status-panels__tabs { padding: 0 var(--mint-section-card-inset); }
|
|
109
|
+
.mint-status-panels__body { padding: 0.75rem var(--mint-section-card-inset); }
|
|
110
110
|
.mint-status-panels__bar { display: flex; flex-direction: column; gap: 0.5rem; }
|
|
111
111
|
.mint-status-panels__series { align-self: flex-end; }
|
|
112
|
-
.mint-status-panels__kv { margin: 0; padding: 0.25rem
|
|
112
|
+
.mint-status-panels__kv { margin: 0; padding: 0.25rem var(--mint-section-card-inset) 0.5rem; }
|
|
113
113
|
.mint-status-panels__kv-row {
|
|
114
114
|
display: flex;
|
|
115
115
|
align-items: baseline;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/** One-card page region from the MINT 1.1 card system: 12px radius, the
|
|
3
3
|
* single --card-shadow token, a header strip (icon chip, title, mono count,
|
|
4
4
|
* actions), and hairline-separated content — no card-in-card. */
|
|
5
|
-
import { computed } from 'vue'
|
|
5
|
+
import { computed, useId } from 'vue'
|
|
6
6
|
import type { SectionCardAccent, SectionCardDivider } from '../types'
|
|
7
7
|
|
|
8
8
|
interface Props {
|
|
@@ -23,6 +23,8 @@ interface Props {
|
|
|
23
23
|
* definite height (a flex or grid track).
|
|
24
24
|
*/
|
|
25
25
|
fill?: boolean
|
|
26
|
+
/** The title toggles the body; bind `v-model:collapsed` to control or keep the state. */
|
|
27
|
+
collapsible?: boolean
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -32,8 +34,14 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
32
34
|
uppercase: false,
|
|
33
35
|
divider: 'strong',
|
|
34
36
|
fill: false,
|
|
37
|
+
collapsible: false,
|
|
35
38
|
})
|
|
36
39
|
|
|
40
|
+
const collapsed = defineModel<boolean>('collapsed', { default: false })
|
|
41
|
+
const bodyId = useId()
|
|
42
|
+
/** `collapsed` hides content only on a card that also shows the toggle to open it again. */
|
|
43
|
+
const hidden = computed(() => props.collapsible && collapsed.value)
|
|
44
|
+
|
|
37
45
|
const iconPaths = computed(() =>
|
|
38
46
|
props.icon === undefined ? [] : Array.isArray(props.icon) ? props.icon : [props.icon],
|
|
39
47
|
)
|
|
@@ -41,6 +49,7 @@ const iconPaths = computed(() =>
|
|
|
41
49
|
const headerClasses = computed(() => [
|
|
42
50
|
'mint-section-card__header',
|
|
43
51
|
props.divider === 'light' ? 'mint-section-card__header--divider-light' : '',
|
|
52
|
+
hidden.value ? 'mint-section-card__header--collapsed' : '',
|
|
44
53
|
])
|
|
45
54
|
|
|
46
55
|
const titleClasses = computed(() => [
|
|
@@ -51,6 +60,7 @@ const titleClasses = computed(() => [
|
|
|
51
60
|
const cardClasses = computed(() => [
|
|
52
61
|
'mint-section-card',
|
|
53
62
|
props.fill ? 'mint-section-card--fill' : '',
|
|
63
|
+
hidden.value ? 'mint-section-card--collapsed' : '',
|
|
54
64
|
])
|
|
55
65
|
</script>
|
|
56
66
|
|
|
@@ -74,20 +84,46 @@ const cardClasses = computed(() => [
|
|
|
74
84
|
<path v-for="(d, i) in iconPaths" :key="i" :d="d" />
|
|
75
85
|
</svg>
|
|
76
86
|
</span>
|
|
77
|
-
|
|
78
|
-
<
|
|
87
|
+
<!-- Disclosure pattern: the button sits inside the heading, never the reverse. -->
|
|
88
|
+
<h2 :class="titleClasses">
|
|
89
|
+
<button
|
|
90
|
+
v-if="collapsible"
|
|
91
|
+
type="button"
|
|
92
|
+
class="mint-section-card__toggle"
|
|
93
|
+
:aria-expanded="!collapsed"
|
|
94
|
+
:aria-controls="bodyId"
|
|
95
|
+
@click="collapsed = !collapsed"
|
|
96
|
+
>
|
|
97
|
+
{{ title }}
|
|
98
|
+
<span v-if="count !== undefined" class="mint-section-card__count">{{ count }}</span>
|
|
99
|
+
<svg
|
|
100
|
+
class="mint-section-card__chevron"
|
|
101
|
+
viewBox="0 0 24 24"
|
|
102
|
+
fill="none"
|
|
103
|
+
stroke="currentColor"
|
|
104
|
+
stroke-width="2"
|
|
105
|
+
stroke-linecap="round"
|
|
106
|
+
stroke-linejoin="round"
|
|
107
|
+
aria-hidden="true"
|
|
108
|
+
>
|
|
109
|
+
<path d="m6 9 6 6 6-6" />
|
|
110
|
+
</svg>
|
|
111
|
+
</button>
|
|
112
|
+
<template v-else>{{ title }}</template>
|
|
113
|
+
</h2>
|
|
114
|
+
<span v-if="count !== undefined && !collapsible" class="mint-section-card__count">{{ count }}</span>
|
|
79
115
|
<div class="mint-section-card__spacer"></div>
|
|
80
116
|
<slot name="actions" />
|
|
81
117
|
</div>
|
|
82
118
|
<!-- Controls belong to the card's chrome, so they sit outside the body and
|
|
83
119
|
stay put while the body scrolls. -->
|
|
84
|
-
<div v-if="$slots.toolbar" class="mint-section-card__toolbar">
|
|
120
|
+
<div v-if="$slots.toolbar" v-show="!hidden" class="mint-section-card__toolbar">
|
|
85
121
|
<slot name="toolbar" />
|
|
86
122
|
</div>
|
|
87
|
-
<div class="mint-section-card__body">
|
|
123
|
+
<div :id="bodyId" v-show="!hidden" class="mint-section-card__body">
|
|
88
124
|
<slot />
|
|
89
125
|
</div>
|
|
90
|
-
<div v-if="$slots.footer" class="mint-section-card__footer">
|
|
126
|
+
<div v-if="$slots.footer" v-show="!hidden" class="mint-section-card__footer">
|
|
91
127
|
<slot name="footer" />
|
|
92
128
|
</div>
|
|
93
129
|
</section>
|
|
@@ -677,16 +677,27 @@ export function useJobsEndpoint(
|
|
|
677
677
|
]))
|
|
678
678
|
jobs.value = nextJobs
|
|
679
679
|
for (const job of nextJobs) settleJobWaiters(job)
|
|
680
|
-
for (const jobId of
|
|
681
|
-
if (!nextJobIds.has(jobId))
|
|
682
|
-
rejectJobWaiters(jobId, new Error(`Job ${jobId} is no longer available`))
|
|
683
|
-
}
|
|
680
|
+
for (const jobId of [...jobWaiters.keys()]) {
|
|
681
|
+
if (!nextJobIds.has(jobId)) void confirmMissingJob(jobId)
|
|
684
682
|
}
|
|
685
683
|
pruneResultState()
|
|
686
684
|
pruneJobRevisions()
|
|
687
685
|
return nextJobs
|
|
688
686
|
}
|
|
689
687
|
|
|
688
|
+
/**
|
|
689
|
+
* A stream snapshot built before a submit can arrive after the submit reply,
|
|
690
|
+
* so a waited job missing from it is gone only once the server says so.
|
|
691
|
+
*/
|
|
692
|
+
async function confirmMissingJob(jobId: string): Promise<void> {
|
|
693
|
+
try {
|
|
694
|
+
await getJob(jobId)
|
|
695
|
+
} catch (cause) {
|
|
696
|
+
if (isRetryableJobLookupError(cause)) return
|
|
697
|
+
rejectJobWaiters(jobId, new Error(`Job ${jobId} is no longer available`))
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
690
701
|
function upsertJob(
|
|
691
702
|
input: GeneratedAnalysisJobInput,
|
|
692
703
|
fallbackDefinitionId?: string,
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
min-height: 0;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/* A collapsed fill card gives its track back to its siblings. */
|
|
31
|
+
.mint-section-card--fill.mint-section-card--collapsed {
|
|
32
|
+
flex: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
.mint-section-card--fill .mint-section-card__body {
|
|
31
36
|
flex: 1;
|
|
32
37
|
min-height: 0;
|
|
@@ -41,7 +46,7 @@
|
|
|
41
46
|
min-height: 2.5rem;
|
|
42
47
|
/* 4px block padding: a 28px header control plus padding plus the 1px rule
|
|
43
48
|
stays inside the 40px strip (6px made it 41px). */
|
|
44
|
-
padding: 0.25rem 0.625rem 0.25rem
|
|
49
|
+
padding: 0.25rem 0.625rem 0.25rem var(--mint-section-card-inset);
|
|
45
50
|
border-bottom: 1px solid var(--border-color);
|
|
46
51
|
flex-shrink: 0;
|
|
47
52
|
}
|
|
@@ -50,6 +55,45 @@
|
|
|
50
55
|
border-bottom-color: var(--border-light);
|
|
51
56
|
}
|
|
52
57
|
|
|
58
|
+
/* A collapsed card is its header alone: no rule under it. */
|
|
59
|
+
.mint-section-card__header--collapsed {
|
|
60
|
+
border-bottom-color: transparent;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.mint-section-card__toggle {
|
|
64
|
+
display: inline-flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
gap: var(--mint-section-card-gap);
|
|
67
|
+
margin: 0;
|
|
68
|
+
padding: 0;
|
|
69
|
+
border: 0;
|
|
70
|
+
background: none;
|
|
71
|
+
color: inherit;
|
|
72
|
+
font: inherit;
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.mint-section-card__toggle:focus-visible {
|
|
77
|
+
outline: none;
|
|
78
|
+
box-shadow: var(--focus-ring-offset);
|
|
79
|
+
border-radius: var(--radius-sm);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.mint-section-card__chevron {
|
|
83
|
+
width: 0.875rem;
|
|
84
|
+
height: 0.875rem;
|
|
85
|
+
color: var(--text-muted);
|
|
86
|
+
transition: transform var(--mint-transition);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.mint-section-card__toggle[aria-expanded="false"] .mint-section-card__chevron {
|
|
90
|
+
transform: rotate(-90deg);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.mint-section-card__toggle:hover .mint-section-card__chevron {
|
|
94
|
+
color: var(--text-secondary);
|
|
95
|
+
}
|
|
96
|
+
|
|
53
97
|
/* Muted icon, no tinted chip: every accent renders the same. */
|
|
54
98
|
.mint-section-card__icon-chip {
|
|
55
99
|
display: inline-flex;
|
|
@@ -97,7 +141,8 @@
|
|
|
97
141
|
display: flex;
|
|
98
142
|
align-items: center;
|
|
99
143
|
justify-content: space-between;
|
|
100
|
-
|
|
144
|
+
/* Text starts on the card inset; controls end where the header's do. */
|
|
145
|
+
padding: 0.5rem 0.625rem 0.5rem var(--mint-section-card-inset);
|
|
101
146
|
border-top: 1px solid var(--border-color);
|
|
102
147
|
background: var(--bg-primary);
|
|
103
148
|
font-size: 0.75rem;
|
|
@@ -118,7 +163,7 @@
|
|
|
118
163
|
display: flex;
|
|
119
164
|
align-items: center;
|
|
120
165
|
gap: var(--mint-section-card-gap);
|
|
121
|
-
padding: 0.375rem
|
|
166
|
+
padding: 0.375rem var(--mint-section-card-inset);
|
|
122
167
|
background: var(--bg-secondary);
|
|
123
168
|
transition: background-color var(--mint-transition);
|
|
124
169
|
}
|
|
@@ -153,12 +198,26 @@ button.mint-section-card__row:hover {
|
|
|
153
198
|
/* Comfortable density gives the header and rows back their height. */
|
|
154
199
|
[data-density="comfortable"] .mint-section-card__header {
|
|
155
200
|
min-height: 2.75rem;
|
|
156
|
-
padding: 0.
|
|
201
|
+
padding-right: 0.75rem;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
[data-density="comfortable"] .mint-section-card__footer {
|
|
205
|
+
padding-right: 0.75rem;
|
|
157
206
|
}
|
|
158
207
|
|
|
159
208
|
[data-density="comfortable"] .mint-section-card__row {
|
|
160
209
|
padding-top: 0.5rem;
|
|
161
210
|
padding-bottom: 0.5rem;
|
|
162
|
-
|
|
163
|
-
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/* A table that is the card body's own child starts and ends on the card's text
|
|
214
|
+
inset, so its first column lines up under the header title. A table inside a
|
|
215
|
+
padded wrapper keeps its padding, and the checkbox and actions columns stay
|
|
216
|
+
centred controls. The table's size padding uses !important, so this must too. */
|
|
217
|
+
.mint-section-card__body > .mint-dataframe :is(.mint-dataframe__th, .mint-dataframe__td):first-child:not(.mint-dataframe__th--checkbox, .mint-dataframe__td--checkbox) {
|
|
218
|
+
padding-left: var(--mint-section-card-inset) !important;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.mint-section-card__body > .mint-dataframe :is(.mint-dataframe__th, .mint-dataframe__td):last-child:not(.mint-dataframe__th--actions, .mint-dataframe__td--actions) {
|
|
222
|
+
padding-right: var(--mint-section-card-inset) !important;
|
|
164
223
|
}
|
package/src/styles/variables.css
CHANGED
|
@@ -134,6 +134,9 @@
|
|
|
134
134
|
--mint-gutter: 0.5rem;
|
|
135
135
|
/* Distance from the outermost cards to the window edge, in every density. */
|
|
136
136
|
--mint-page-inset: 1rem;
|
|
137
|
+
/* Text inset of a SectionCard: its title, row text and table edge columns
|
|
138
|
+
start here, and page chrome over a card (breadcrumbs) can line up with it. */
|
|
139
|
+
--mint-section-card-inset: 0.75rem;
|
|
137
140
|
|
|
138
141
|
/* Semantic colors */
|
|
139
142
|
--mint-success: #10B981;
|
|
@@ -377,6 +380,7 @@ html.dark [data-palette="forest"] {
|
|
|
377
380
|
/* Comfortable density (html[data-density], written by the settings store):
|
|
378
381
|
the pre-v2 control heights and a wider gutter. */
|
|
379
382
|
[data-density="comfortable"] {
|
|
383
|
+
--mint-section-card-inset: 0.875rem;
|
|
380
384
|
--form-height-sm: 2rem;
|
|
381
385
|
--form-height-md: 2.25rem;
|
|
382
386
|
--form-height-lg: 3rem;
|