codex/promote-grouped-stock-view #7
@@ -300,144 +300,158 @@ export function renderStockListPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-body p-4">
|
||||
<div class="d-flex justify-content-between align-items-center gap-3 mb-3">
|
||||
<label class="form-label mb-0">Search stock</label>
|
||||
<button class="btn btn-link p-0 text-decoration-none stock-filter-reset" type="button" @click="clearFilters()">Reset</button>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
x-model.debounce.250ms="filters.search"
|
||||
placeholder="Search by item, description, location, or id"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mb-4 align-items-start" :class="overviewRowClass()">
|
||||
<div class="col-12" :class="overviewColClass('expiration')">
|
||||
<details
|
||||
class="card border-0 shadow-sm overview-panel"
|
||||
x-ref="expirationOverview"
|
||||
@toggle="setOverviewOpen('expiration', $event.target.open)"
|
||||
>
|
||||
<summary class="card-body p-4 overview-summary">
|
||||
<div class="d-flex justify-content-between align-items-start gap-3">
|
||||
<div class="row g-4 stock-workspace">
|
||||
<aside class="col-12 col-xl-4 col-xxl-3 stock-filter-rail">
|
||||
<div class="card border-0 shadow-sm stock-filter-hub">
|
||||
<div class="card-body p-4">
|
||||
<div class="d-flex flex-column gap-2 mb-3">
|
||||
<div>
|
||||
<h2 class="h5 mb-1">Expiration overview</h2>
|
||||
<p class="text-body-secondary small mb-0">Tap to focus on one or more expiration states.</p>
|
||||
<h2 class="h5 mb-1">Search and filters</h2>
|
||||
<p class="text-body-secondary small mb-0">
|
||||
Focus the stock list with one control panel.
|
||||
</p>
|
||||
</div>
|
||||
<div class="d-flex flex-column align-items-end gap-1">
|
||||
<button class="btn btn-link p-0 text-decoration-none stock-filter-reset" type="button" @click.prevent.stop="toggleAllExpirationFilters()">Show all</button>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<button class="btn btn-link p-0 text-decoration-none stock-filter-reset" type="button" @click="clearFilters()">Reset all</button>
|
||||
<div class="small text-body-secondary text-end">
|
||||
<span class="fw-semibold text-body" x-text="visibleResultCount"></span>
|
||||
<span x-text="viewMode === 'grouped' ? 'group(s) visible' : 'item(s) visible'"></span>
|
||||
<span x-text="viewMode === 'grouped' ? 'group(s)' : 'item(s)'"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</summary>
|
||||
<div class="card-body pt-0 px-4 pb-4">
|
||||
<div class="overview-list" :class="{ 'overview-list-split': isOnlyOverviewOpen('expiration') }">
|
||||
<template x-for="stateInfo in expirationLegend" :key="stateInfo.key">
|
||||
<button
|
||||
class="overview-option text-start"
|
||||
type="button"
|
||||
:class="legendClass(stateInfo.key)"
|
||||
@click="toggleExpirationOverviewFilter(stateInfo.key)"
|
||||
:aria-pressed="isExpirationFilterActive(stateInfo.key)"
|
||||
>
|
||||
<div class="d-flex justify-content-between align-items-start gap-3 mb-1">
|
||||
<div class="fw-semibold" x-text="stateInfo.label"></div>
|
||||
<div class="small fw-semibold" x-text="expirationCount(stateInfo.key)"></div>
|
||||
</div>
|
||||
<div class="small" x-text="stateInfo.description"></div>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label mb-1">Search stock</label>
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
x-model.debounce.250ms="filters.search"
|
||||
placeholder="Search by item, description, location, or id"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<div class="col-12" :class="overviewColClass('location')">
|
||||
<details
|
||||
class="card border-0 shadow-sm overview-panel"
|
||||
x-ref="locationOverview"
|
||||
@toggle="setOverviewOpen('location', $event.target.open)"
|
||||
>
|
||||
<summary class="card-body p-4 overview-summary">
|
||||
<div class="d-flex justify-content-between align-items-start gap-3">
|
||||
<div>
|
||||
<h2 class="h5 mb-1">Location overview</h2>
|
||||
<p class="text-body-secondary small mb-0">Tap locations to focus the list. Parent locations include their children.</p>
|
||||
</div>
|
||||
<div class="d-flex flex-column align-items-end gap-1">
|
||||
<button class="btn btn-link p-0 text-decoration-none stock-filter-reset" type="button" @click.prevent.stop="toggleAllLocations()">Show all</button>
|
||||
<div class="small text-body-secondary text-end" x-text="selectedLocationSummary()"></div>
|
||||
|
||||
<div class="stock-filter-summary mb-3">
|
||||
<div class="small text-body-secondary mb-2">Active scope</div>
|
||||
<div class="d-grid gap-1">
|
||||
<div class="small"><span class="fw-semibold">Expiration:</span> <span x-text="expirationFilterSummary()"></span></div>
|
||||
<div class="small"><span class="fw-semibold">Location:</span> <span x-text="locationFilterSummary()"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</summary>
|
||||
<div class="card-body pt-0 px-4 pb-4">
|
||||
<template x-if="isOnlyOverviewOpen('location')">
|
||||
<div class="overview-list overview-list-locations location-overview-columns">
|
||||
<template x-for="(columnGroups, columnIndex) in balancedLocationOverviewColumns()" :key="columnIndex">
|
||||
<div class="location-overview-column">
|
||||
<template x-for="group in columnGroups" :key="group.parent.id">
|
||||
<div class="location-overview-group">
|
||||
<template x-for="location in group.items" :key="location.id">
|
||||
<button
|
||||
class="overview-option overview-option-location text-start"
|
||||
type="button"
|
||||
:class="locationOverviewClass(location)"
|
||||
:style="locationOverviewStyle(location)"
|
||||
@click="toggleLocationOverviewFilter(location.uuid_b64)"
|
||||
:aria-pressed="isLocationFilterActive(location.uuid_b64)"
|
||||
>
|
||||
<span class="stock-filter-location-rail" x-show="location.depth"></span>
|
||||
<div class="d-flex justify-content-between align-items-start gap-3">
|
||||
<div class="fw-semibold" :class="location.depth ? 'small mb-0' : ''" x-text="location.name"></div>
|
||||
<div class="small fw-semibold" x-text="locationCount(location.uuid_b64)"></div>
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div
|
||||
class="d-grid gap-3 stock-filter-panels"
|
||||
:class="{ 'stock-filter-panels-single-open': openOverviewCount() > 0 }"
|
||||
>
|
||||
<details
|
||||
class="overview-panel stock-filter-panel-card"
|
||||
x-ref="expirationOverview"
|
||||
@toggle="setOverviewOpen('expiration', $event.target.open)"
|
||||
>
|
||||
<summary class="p-3 overview-summary">
|
||||
<div class="d-flex justify-content-between align-items-start gap-3">
|
||||
<div>
|
||||
<h3 class="h6 mb-1">Expiration overview</h3>
|
||||
<p class="text-body-secondary small mb-0">Tap to focus expiration states.</p>
|
||||
</div>
|
||||
<button class="btn btn-link p-0 text-decoration-none stock-filter-reset" type="button" @click.prevent.stop="toggleAllExpirationFilters()">Show all</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="!isOnlyOverviewOpen('location')">
|
||||
<div class="overview-list overview-list-locations">
|
||||
<template x-for="group in locationOverviewGroups()" :key="group.parent.id">
|
||||
<div class="location-overview-group">
|
||||
<template x-for="location in group.items" :key="location.id">
|
||||
</summary>
|
||||
<div class="pt-0 px-3 pb-3">
|
||||
<div class="overview-list">
|
||||
<template x-for="stateInfo in expirationLegend" :key="stateInfo.key">
|
||||
<button
|
||||
class="overview-option overview-option-location text-start"
|
||||
class="overview-option text-start"
|
||||
type="button"
|
||||
:class="locationOverviewClass(location)"
|
||||
:style="locationOverviewStyle(location)"
|
||||
@click="toggleLocationOverviewFilter(location.uuid_b64)"
|
||||
:aria-pressed="isLocationFilterActive(location.uuid_b64)"
|
||||
:class="legendClass(stateInfo.key)"
|
||||
@click="toggleExpirationOverviewFilter(stateInfo.key)"
|
||||
:aria-pressed="isExpirationFilterActive(stateInfo.key)"
|
||||
>
|
||||
<span class="stock-filter-location-rail" x-show="location.depth"></span>
|
||||
<div class="d-flex justify-content-between align-items-start gap-3">
|
||||
<div class="fw-semibold" :class="location.depth ? 'small mb-0' : ''" x-text="location.name"></div>
|
||||
<div class="small fw-semibold" x-text="locationCount(location.uuid_b64)"></div>
|
||||
<div class="d-flex justify-content-between align-items-start gap-3 mb-1">
|
||||
<div class="fw-semibold" x-text="stateInfo.label"></div>
|
||||
<div class="small fw-semibold" x-text="expirationCount(stateInfo.key)"></div>
|
||||
</div>
|
||||
<div class="small" x-text="stateInfo.description"></div>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details
|
||||
class="overview-panel stock-filter-panel-card"
|
||||
x-ref="locationOverview"
|
||||
@toggle="setOverviewOpen('location', $event.target.open)"
|
||||
>
|
||||
<summary class="p-3 overview-summary">
|
||||
<div class="d-flex justify-content-between align-items-start gap-3">
|
||||
<div>
|
||||
<h3 class="h6 mb-1">Location overview</h3>
|
||||
<p class="text-body-secondary small mb-0">Parent locations include children.</p>
|
||||
</div>
|
||||
<button class="btn btn-link p-0 text-decoration-none stock-filter-reset" type="button" @click.prevent.stop="toggleAllLocations()">Show all</button>
|
||||
</div>
|
||||
</summary>
|
||||
<div class="pt-0 px-3 pb-3">
|
||||
<template x-if="isOnlyOverviewOpen('location')">
|
||||
<div class="overview-list overview-list-locations location-overview-columns">
|
||||
<template x-for="(columnGroups, columnIndex) in balancedLocationOverviewColumns()" :key="columnIndex">
|
||||
<div class="location-overview-column">
|
||||
<template x-for="group in columnGroups" :key="group.parent.id">
|
||||
<div class="location-overview-group">
|
||||
<template x-for="location in group.items" :key="location.id">
|
||||
<button
|
||||
class="overview-option overview-option-location text-start"
|
||||
type="button"
|
||||
:class="locationOverviewClass(location)"
|
||||
:style="locationOverviewStyle(location)"
|
||||
@click="toggleLocationOverviewFilter(location.uuid_b64)"
|
||||
:aria-pressed="isLocationFilterActive(location.uuid_b64)"
|
||||
>
|
||||
<span class="stock-filter-location-rail" x-show="location.depth"></span>
|
||||
<div class="d-flex justify-content-between align-items-start gap-3">
|
||||
<div class="fw-semibold" :class="location.depth ? 'small mb-0' : ''" x-text="location.name"></div>
|
||||
<div class="small fw-semibold" x-text="locationCount(location.uuid_b64)"></div>
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="!isOnlyOverviewOpen('location')">
|
||||
<div class="overview-list overview-list-locations">
|
||||
<template x-for="group in locationOverviewGroups()" :key="group.parent.id">
|
||||
<div class="location-overview-group">
|
||||
<template x-for="location in group.items" :key="location.id">
|
||||
<button
|
||||
class="overview-option overview-option-location text-start"
|
||||
type="button"
|
||||
:class="locationOverviewClass(location)"
|
||||
:style="locationOverviewStyle(location)"
|
||||
@click="toggleLocationOverviewFilter(location.uuid_b64)"
|
||||
:aria-pressed="isLocationFilterActive(location.uuid_b64)"
|
||||
>
|
||||
<span class="stock-filter-location-rail" x-show="location.depth"></span>
|
||||
<div class="d-flex justify-content-between align-items-start gap-3">
|
||||
<div class="fw-semibold" :class="location.depth ? 'small mb-0' : ''" x-text="location.name"></div>
|
||||
<div class="small fw-semibold" x-text="locationCount(location.uuid_b64)"></div>
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="col-12 col-xl-8 col-xxl-9 stock-results-pane">
|
||||
<template x-if="showInitialLoader()">
|
||||
<div class="alert alert-secondary">Loading stock review...</div>
|
||||
</template>
|
||||
@@ -630,29 +644,28 @@ export function renderStockListPage() {
|
||||
:data-group-id="String(group.id)"
|
||||
@toggle="handleGroupedToggle($event)"
|
||||
>
|
||||
<summary class="card-body p-4 grouped-stock-summary">
|
||||
<div class="d-flex flex-column flex-xl-row justify-content-between gap-3">
|
||||
<summary class="card-body p-3 grouped-stock-summary">
|
||||
<div class="d-flex flex-column flex-xl-row justify-content-between gap-2 grouped-stock-summary-row">
|
||||
<div>
|
||||
<div class="fw-semibold fs-5" x-text="group.name"></div>
|
||||
<div class="text-body-secondary small mb-2" x-text="group.description || 'No description'"></div>
|
||||
<div class="fw-semibold grouped-stock-summary-title" x-text="group.name"></div>
|
||||
<div class="text-body-secondary small grouped-stock-summary-description" x-show="group.description" x-text="group.description"></div>
|
||||
<div class="d-flex flex-wrap gap-3 small grouped-stock-summary-meta">
|
||||
<span><span class="fw-semibold text-body" x-text="groupItemCount(group)"></span> item(s)</span>
|
||||
<span><span class="text-body-secondary">Latest location:</span> <span class="fw-semibold text-body" x-text="locationLabel(group)"></span></span>
|
||||
<span><span class="text-body-secondary">Latest quantity:</span> <span class="fw-semibold text-body" x-text="quantityLabel(group)"></span></span>
|
||||
</div>
|
||||
<a class="small text-decoration-none fw-semibold d-inline-block mt-2" :href="groupDetailHref(group)" x-show="groupDetailHref(group)">View item</a>
|
||||
</div>
|
||||
<div class="d-flex flex-column align-items-xl-end gap-2">
|
||||
<span class="badge rounded-pill align-self-start align-self-xl-end" :class="badgeClass(group)" x-text="expirationFor(group).label"></span>
|
||||
<div class="small text-body-secondary text-xl-end">
|
||||
<div class="grouped-stock-summary-status">
|
||||
<span class="badge rounded-pill" :class="badgeClass(group)" x-text="expirationFor(group).label"></span>
|
||||
<div class="small text-body-secondary">
|
||||
<span class="text-body-secondary">First expires:</span>
|
||||
<span x-text="expirationFor(group).detail"></span>
|
||||
</div>
|
||||
<div class="small fw-semibold grouped-stock-toggle-label">Show items</div>
|
||||
<div class="small fw-semibold grouped-stock-toggle-label">Items</div>
|
||||
</div>
|
||||
</div>
|
||||
</summary>
|
||||
<div class="card-body pt-0 px-4 pb-4">
|
||||
<div class="card-body pt-0 px-4 pb-3">
|
||||
<div class="grouped-stock-secondary-details mb-3">
|
||||
<details class="grouped-stock-secondary-toggle">
|
||||
<summary class="small fw-semibold">More dates and metadata</summary>
|
||||
@@ -679,24 +692,28 @@ export function renderStockListPage() {
|
||||
<div class="grouped-stock-items">
|
||||
<template x-for="item in group.items" :key="item.id">
|
||||
<div class="grouped-stock-item" :class="groupedItemClass(item)">
|
||||
<div class="d-flex flex-column flex-lg-row justify-content-between gap-2">
|
||||
<div>
|
||||
<div class="fw-semibold" x-text="item.name"></div>
|
||||
<div class="grouped-stock-item-row">
|
||||
<div class="grouped-stock-item-main">
|
||||
<div class="grouped-stock-item-title-line">
|
||||
<div class="fw-semibold grouped-stock-item-name" x-text="item.name"></div>
|
||||
<span class="font-monospace grouped-stock-item-id" x-text="shortId(item)"></span>
|
||||
</div>
|
||||
<div class="small text-body-secondary grouped-stock-item-subline">
|
||||
<span x-text="locationLabel(item)"></span>
|
||||
<span class="grouped-stock-subline-separator" aria-hidden="true">•</span>
|
||||
<span x-text="shortDescription(item.description)"></span>
|
||||
</div>
|
||||
<a class="small text-decoration-none fw-semibold" :href="detailHref(item)">View item</a>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-3 small text-body-secondary grouped-stock-item-meta">
|
||||
<div class="small text-body-secondary grouped-stock-item-aux">
|
||||
<span x-text="quantityLabel(item)"></span>
|
||||
<span class="grouped-stock-date-pair">
|
||||
<span x-text="formatDate(item.date)"></span>
|
||||
<span class="grouped-stock-date-separator" aria-hidden="true">→</span>
|
||||
<span x-text="formatDate(item.expire_date)"></span>
|
||||
</span>
|
||||
<span class="font-monospace" x-text="shortId(item)"></span>
|
||||
</div>
|
||||
<div class="grouped-stock-item-actions">
|
||||
<a class="text-decoration-none fw-semibold grouped-stock-item-link" :href="detailHref(item)">Details</a>
|
||||
<button class="btn btn-sm btn-outline-danger grouped-stock-mark-gone" type="button" @click="markGoneFromGroup(item, group)">Mark gone</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -716,13 +733,13 @@ export function renderStockListPage() {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="mt-3 d-flex justify-content-end">
|
||||
<div class="grouped-stock-close-row">
|
||||
<button
|
||||
class="btn btn-link p-0 text-decoration-none grouped-stock-close"
|
||||
class="btn btn-link text-decoration-none grouped-stock-close"
|
||||
type="button"
|
||||
@click.prevent="closeGroupedCard($el.closest('details'))"
|
||||
>
|
||||
Close group
|
||||
Collapse group
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -737,6 +754,8 @@ export function renderStockListPage() {
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
@@ -1145,13 +1164,6 @@ export function stockListPageData(store) {
|
||||
}
|
||||
return Array.isArray(group.items) ? group.items.length : 0;
|
||||
},
|
||||
groupDetailHref(group) {
|
||||
if (group?.uuid_b64) {
|
||||
return this.detailHref(group);
|
||||
}
|
||||
const firstItem = Array.isArray(group?.items) ? group.items[0] : null;
|
||||
return firstItem?.uuid_b64 ? this.detailHref(firstItem) : '';
|
||||
},
|
||||
isGroupedCardOpen(groupId) {
|
||||
return Boolean(this.openGroupedCards[String(groupId)]);
|
||||
},
|
||||
@@ -1228,6 +1240,30 @@ export function stockListPageData(store) {
|
||||
}
|
||||
return unique;
|
||||
},
|
||||
expirationFilterSummary() {
|
||||
const active = this.effectiveExpirationFilters();
|
||||
if (!active.length) {
|
||||
return 'All states';
|
||||
}
|
||||
|
||||
if (active.length === 1) {
|
||||
return this.expirationLegend.find((state) => state.key === active[0])?.label || '1 state';
|
||||
}
|
||||
|
||||
return `${active.length} states selected`;
|
||||
},
|
||||
locationFilterSummary() {
|
||||
const active = this.effectiveLocationFilters();
|
||||
if (!active.length) {
|
||||
return 'All locations';
|
||||
}
|
||||
|
||||
if (active.length === 1) {
|
||||
return this.locationMap[active[0]] || '1 location selected';
|
||||
}
|
||||
|
||||
return `${active.length} locations selected`;
|
||||
},
|
||||
normalizedSearchTerm() {
|
||||
return String(this.filters.search || '').trim().toLowerCase();
|
||||
},
|
||||
|
||||
+193
-9
@@ -314,6 +314,54 @@ body {
|
||||
color: var(--lonc-primary);
|
||||
}
|
||||
|
||||
.stock-filter-hub {
|
||||
background:
|
||||
linear-gradient(160deg, rgba(255, 255, 255, 0.94), rgba(245, 250, 255, 0.88)),
|
||||
linear-gradient(135deg, rgba(93, 169, 255, 0.1), rgba(31, 75, 153, 0.06));
|
||||
}
|
||||
|
||||
.stock-workspace {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.stock-results-pane {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.stock-filter-summary {
|
||||
padding: 0.85rem 0.95rem;
|
||||
border-radius: 0.9rem;
|
||||
border: 1px dashed rgba(31, 75, 153, 0.24);
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.stock-filter-rail .overview-list-locations {
|
||||
max-height: 18rem;
|
||||
}
|
||||
|
||||
.stock-filter-rail .location-overview-columns {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 1199.98px) {
|
||||
.stock-filter-panels {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.stock-filter-panels.stock-filter-panels-single-open {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.stock-filter-rail .stock-filter-hub {
|
||||
position: sticky;
|
||||
top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.stock-view-switch {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
@@ -383,6 +431,16 @@ body {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.stock-filter-panel-card {
|
||||
border: 1px solid var(--lonc-border);
|
||||
border-radius: 1rem;
|
||||
background: rgba(255, 255, 255, 0.84);
|
||||
}
|
||||
|
||||
.stock-filter-panel-card[open] {
|
||||
box-shadow: 0 10px 24px rgba(24, 42, 79, 0.08);
|
||||
}
|
||||
|
||||
.overview-summary {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
@@ -646,6 +704,19 @@ button.legend-card:focus-visible {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.grouped-stock-summary-row {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.grouped-stock-summary-title {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.grouped-stock-summary-description {
|
||||
margin: 0.12rem 0 0.35rem;
|
||||
}
|
||||
|
||||
.grouped-stock-summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
@@ -655,6 +726,14 @@ button.legend-card:focus-visible {
|
||||
row-gap: 0.35rem;
|
||||
}
|
||||
|
||||
.grouped-stock-summary-status {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 0.4rem 0.75rem;
|
||||
}
|
||||
|
||||
.grouped-stock-secondary-details {
|
||||
border-top: 1px dashed rgba(31, 39, 64, 0.14);
|
||||
padding-top: 0.75rem;
|
||||
@@ -678,11 +757,13 @@ button.legend-card:focus-visible {
|
||||
|
||||
.grouped-stock-toggle-label {
|
||||
color: var(--lonc-primary);
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.grouped-stock-toggle-label::after {
|
||||
content: 'Expand';
|
||||
margin-left: 0.35rem;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.grouped-stock-card[open] .grouped-stock-toggle-label::after {
|
||||
@@ -709,14 +790,20 @@ button.legend-card:focus-visible {
|
||||
border-left-color: #6c757d;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.grouped-stock-summary-status {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.grouped-stock-items {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
gap: 0.55rem;
|
||||
}
|
||||
|
||||
.grouped-stock-item {
|
||||
display: block;
|
||||
padding: 0.9rem 1rem;
|
||||
padding: 0.65rem 0.8rem;
|
||||
border-radius: 0.95rem;
|
||||
border: 1px solid var(--lonc-border);
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
@@ -753,12 +840,56 @@ button.legend-card:focus-visible {
|
||||
background: rgba(108, 117, 125, 0.08);
|
||||
}
|
||||
|
||||
.grouped-stock-item-meta {
|
||||
justify-content: flex-start;
|
||||
.grouped-stock-item-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.grouped-stock-item-main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.grouped-stock-item-title-line {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.grouped-stock-item-name {
|
||||
font-size: 1rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.grouped-stock-item-id {
|
||||
color: var(--lonc-muted);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.grouped-stock-item-aux {
|
||||
display: grid;
|
||||
gap: 0.2rem;
|
||||
text-align: right;
|
||||
justify-items: end;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.grouped-stock-item-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.grouped-stock-item-link {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.grouped-stock-mark-gone {
|
||||
align-self: center;
|
||||
padding: 0.2rem 0.55rem;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -784,9 +915,62 @@ button.legend-card:focus-visible {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.grouped-stock-item-meta {
|
||||
justify-content: flex-end;
|
||||
.grouped-stock-close-row {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 0.2rem;
|
||||
padding-top: 0.2rem;
|
||||
border-top: 1px dashed rgba(31, 39, 64, 0.12);
|
||||
}
|
||||
|
||||
.grouped-stock-close {
|
||||
padding: 0.1rem 0.2rem;
|
||||
font-size: 0.78rem;
|
||||
color: rgba(31, 39, 64, 0.82);
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.grouped-stock-close:hover {
|
||||
color: var(--lonc-primary-dark);
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.grouped-stock-item-row {
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.grouped-stock-item-actions {
|
||||
grid-column: 1 / -1;
|
||||
justify-content: space-between;
|
||||
padding-top: 0.15rem;
|
||||
}
|
||||
|
||||
.grouped-stock-item-aux {
|
||||
text-align: left;
|
||||
justify-items: start;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 575.98px) {
|
||||
.grouped-stock-item {
|
||||
padding: 0.6rem 0.7rem;
|
||||
}
|
||||
|
||||
.grouped-stock-item-row {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.grouped-stock-item-aux {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.grouped-stock-item-title-line {
|
||||
gap: 0.45rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user