tile design done
This commit is contained in:
parent
d30fd56d4f
commit
1894b1f9a5
@ -65,7 +65,8 @@ export const ORDER_BOOKING = {
|
||||
recordViews: {
|
||||
ORDERS: '1e424561-9a27-44f5-9b68-64d63296d837',
|
||||
CALLS: 'b4d7a710-24e7-416d-885a-31fd1e727aab',
|
||||
ANALYTICS: 'b4d7a710-24e7-416d-885a-31fd1e727aab'
|
||||
ANALYTICS: 'b4d7a710-24e7-416d-885a-31fd1e727aab',
|
||||
|
||||
},
|
||||
detailViews: {
|
||||
ORDERS: '0804c6c3-6cf9-4050-94bb-fa48dd5de87d',
|
||||
|
||||
@ -330,6 +330,13 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
|
||||
const val = values[f.id];
|
||||
const isDisabled = schema.field_defaults?.[f.id]?.disabled || f.properties?.disabled;
|
||||
|
||||
const isPlaceOrder = currentActivityId === ORDER_BOOKING.activities.PLACE_ORDER.uid;
|
||||
const isOrderId = f.name.toLowerCase() === 'order id' || f.id.toLowerCase().includes('order_id') || f.mapped_workflow_field === 'order_id';
|
||||
|
||||
if (isPlaceOrder && isOrderId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const renderField = () => {
|
||||
if (type === 'wf_lookup') {
|
||||
return (
|
||||
|
||||
@ -29,9 +29,10 @@ export function FileInput({
|
||||
const files = Array.isArray(value) ? value : (value instanceof File ? [value] : []);
|
||||
|
||||
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.files) {
|
||||
if (e.target.files && e.target.files.length > 0) {
|
||||
const newFiles = Array.from(e.target.files);
|
||||
onChange([...files, ...newFiles]);
|
||||
// Since we only want 1 file, replace the existing one instead of appending
|
||||
onChange(newFiles);
|
||||
}
|
||||
// reset input so the same file can be selected again if needed
|
||||
e.target.value = '';
|
||||
@ -53,7 +54,6 @@ export function FileInput({
|
||||
<div className="flex flex-col gap-3">
|
||||
<input
|
||||
type="file"
|
||||
multiple
|
||||
required={required && files.length === 0}
|
||||
accept={type === 'image' ? 'image/*' : undefined}
|
||||
onChange={handleFileChange}
|
||||
@ -63,7 +63,7 @@ export function FileInput({
|
||||
{files.length > 0 && (
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{files.map((file, i) => (
|
||||
<div key={i} className="relative w-24 h-24 rounded-md overflow-hidden border border-border-default shadow-sm bg-slate-50 flex-shrink-0 group">
|
||||
<div key={i} className="relative w-24 h-24 rounded-md overflow-hidden border border-border-default shadow-sm bg-slate-50 flex-shrink-0">
|
||||
{type === 'image' ? (
|
||||
<ImagePreview file={file} />
|
||||
) : (
|
||||
@ -74,7 +74,7 @@ export function FileInput({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeFile(i)}
|
||||
className="absolute top-1 right-1 bg-ruby-600/90 hover:bg-ruby-700 text-white rounded-full w-6 h-6 flex items-center justify-center text-xs opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
className="absolute top-1 right-1 bg-ruby-600/90 hover:bg-ruby-700 text-white rounded-full w-6 h-6 flex items-center justify-center text-xs shadow-md"
|
||||
title="Remove file"
|
||||
>
|
||||
✕
|
||||
|
||||
@ -152,6 +152,8 @@ export function SmartGridField({
|
||||
setEditingIdx(null);
|
||||
};
|
||||
|
||||
const isPotentialMining = label.toLowerCase().includes('potential');
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2 font-sans border border-border-default rounded-md p-4 bg-slate-50">
|
||||
<span className="text-sm font-semibold text-strong mb-2">{label}</span>
|
||||
@ -163,32 +165,62 @@ export function SmartGridField({
|
||||
{value.map((row, i) => {
|
||||
let productName = 'Unknown Product';
|
||||
let bags = '0';
|
||||
let hasBagsCol = false;
|
||||
let diffVal: number | null = null;
|
||||
let reasonStr = '';
|
||||
|
||||
visibleColumns.forEach(col => {
|
||||
const isName = col.id.toLowerCase().includes('name') || col.name.toLowerCase().includes('name') || (col.id.toLowerCase().includes('category') && productName === 'Unknown Product');
|
||||
const isBags = col.id.toLowerCase().includes('bags') || col.name.toLowerCase().includes('bags') || col.id.toLowerCase().includes('quantity');
|
||||
const isDiff = col.id.toLowerCase().includes('diff') || col.name.toLowerCase().includes('diff');
|
||||
const isReason = col.id.toLowerCase().includes('reason') || col.name.toLowerCase().includes('reason');
|
||||
|
||||
if (isName || isBags) {
|
||||
const val = row[col.id];
|
||||
let displayVal = String(val ?? '-');
|
||||
const val = row[col.id];
|
||||
let displayVal = String(val ?? '-');
|
||||
|
||||
if (col.data_type === 'select' || col.data_type === 'multiselect') {
|
||||
const opt = col.properties?.options?.find(o => String(o.value) === String(val));
|
||||
if (opt) displayVal = opt.label;
|
||||
}
|
||||
if (col.data_type === 'select' || col.data_type === 'multiselect') {
|
||||
const opt = col.properties?.options?.find(o => String(o.value) === String(val));
|
||||
if (opt) displayVal = opt.label;
|
||||
}
|
||||
|
||||
if (isName && (productName === 'Unknown Product' || col.id.toLowerCase().includes('name'))) {
|
||||
productName = displayVal;
|
||||
}
|
||||
if (isBags) bags = displayVal;
|
||||
if (isName && (productName === 'Unknown Product' || col.id.toLowerCase().includes('name'))) {
|
||||
productName = displayVal;
|
||||
}
|
||||
if (isBags) {
|
||||
bags = displayVal;
|
||||
hasBagsCol = true;
|
||||
}
|
||||
|
||||
if (isPotentialMining && isDiff && val != null && val !== '') {
|
||||
diffVal = Number(val);
|
||||
}
|
||||
|
||||
if (isPotentialMining && isReason && val && displayVal !== 'Select...' && displayVal !== '-') {
|
||||
reasonStr = displayVal;
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div key={i} className="bg-slate-50 border border-slate-200 rounded-xl p-3 shadow-sm flex items-center justify-between">
|
||||
<div className="flex flex-col min-w-0 pr-4">
|
||||
<div className="flex flex-col min-w-0 pr-4 gap-1.5">
|
||||
<span className="font-bold text-slate-800 text-[14px] truncate">{productName}</span>
|
||||
<span className="font-extrabold text-indigo-600 text-[13px] mt-0.5">{bags} Bags</span>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{(!isPotentialMining || hasBagsCol) && (
|
||||
<span className="font-extrabold text-indigo-600 text-[13px]">{bags} Bags</span>
|
||||
)}
|
||||
|
||||
{isPotentialMining && diffVal !== null && !isNaN(diffVal) && diffVal !== 0 && (
|
||||
<span className={`text-[11px] font-bold px-2 py-0.5 rounded-md ${diffVal > 0 ? 'bg-emerald-100 text-emerald-700' : 'bg-red-100 text-red-700'}`}>
|
||||
{Math.abs(diffVal)} {diffVal > 0 ? 'Surplus' : 'Less'}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{isPotentialMining && reasonStr && (
|
||||
<span className="text-[11px] font-medium bg-slate-200 text-slate-700 px-2 py-0.5 rounded-md truncate max-w-[120px]" title={reasonStr}>
|
||||
{reasonStr}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-1.5 shrink-0">
|
||||
|
||||
@ -6,7 +6,8 @@ import {
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
Tooltip,
|
||||
ResponsiveContainer
|
||||
ResponsiveContainer,
|
||||
LabelList
|
||||
} from 'recharts';
|
||||
|
||||
export interface ChartRow {
|
||||
@ -28,7 +29,6 @@ export function AnalyticsChart({ data }: AnalyticsChartProps) {
|
||||
if (!data || !Array.isArray(data) || data.length === 0) return null;
|
||||
|
||||
const charts = data as ChartConfig[];
|
||||
const colors = ['#3B82F6', '#10B981', '#F59E0B', '#8B5CF6', '#EC4899', '#14B8A6'];
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 w-full">
|
||||
@ -46,10 +46,16 @@ export function AnalyticsChart({ data }: AnalyticsChartProps) {
|
||||
if (formattedRows.length === 0) return null;
|
||||
|
||||
return (
|
||||
<Card key={chart.chart_uid || idx} title={title} className="shadow-sm border-t-4 border-t-indigo-500">
|
||||
<Card key={chart.chart_uid || idx} title={title} className="shadow-sm">
|
||||
<div className="h-[320px] w-full mt-4">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart data={formattedRows} margin={{ top: 10, right: 10, left: -20, bottom: 0 }}>
|
||||
<BarChart data={formattedRows} margin={{ top: 25, right: 10, left: -20, bottom: 0 }}>
|
||||
<defs>
|
||||
<linearGradient id={`colorGradient-${idx}`} x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor="var(--primary-color)" stopOpacity={1} />
|
||||
<stop offset="100%" stopColor="var(--primary-color-300)" stopOpacity={1} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#E2E8F0" />
|
||||
<XAxis
|
||||
dataKey="dimension"
|
||||
@ -72,10 +78,12 @@ export function AnalyticsChart({ data }: AnalyticsChartProps) {
|
||||
<Bar
|
||||
dataKey="value"
|
||||
name="Value"
|
||||
fill={colors[idx % colors.length]}
|
||||
radius={[4, 4, 0, 0]}
|
||||
fill={`url(#colorGradient-${idx})`}
|
||||
radius={[8, 8, 0, 0]}
|
||||
maxBarSize={40}
|
||||
/>
|
||||
>
|
||||
<LabelList dataKey="value" position="top" fill="#475569" fontSize={12} fontWeight="bold" />
|
||||
</Bar>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
@ -28,7 +28,7 @@ export function Input({
|
||||
return (
|
||||
<label className={cn('flex flex-col gap-1.5 font-sans', disabled && 'cursor-not-allowed', className)}>
|
||||
{label && (
|
||||
<span className="text-sm font-medium text-muted">
|
||||
<span className="text-sm font-semibold text-slate-700">
|
||||
{label}
|
||||
{required && <span className="text-ruby-600"> *</span>}
|
||||
</span>
|
||||
|
||||
@ -53,7 +53,7 @@ export function Modal({ open, onClose, title, subtitle, width = 'md', actions, c
|
||||
aria-modal="true"
|
||||
className={cn(
|
||||
'relative w-full bg-card rounded-t-2xl sm:rounded-lg border border-border-subtle shadow-lg sm:my-auto',
|
||||
'flex flex-col max-h-[92vh] sm:max-h-[85vh]',
|
||||
'flex flex-col max-h-[70vh]',
|
||||
WIDTH[width],
|
||||
)}
|
||||
>
|
||||
|
||||
@ -21,7 +21,7 @@ export function Select({ label, hint, options = [], required, className, ...rest
|
||||
return (
|
||||
<label className={cn('flex flex-col gap-1.5 font-sans', className)}>
|
||||
{label && (
|
||||
<span className="text-sm font-medium text-muted">
|
||||
<span className="text-sm font-semibold text-slate-700">
|
||||
{label}
|
||||
{required && <span className="text-ruby-600"> *</span>}
|
||||
</span>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { TileItem } from "../../api/types";
|
||||
import { Phone, TrendingUp, Activity, BarChart2, ShoppingCart, ShoppingBag, Scale } from 'lucide-react';
|
||||
import { Phone, TrendingUp, Activity, BarChart2, ShoppingCart, ShoppingBag, Scale, Store, Map } from 'lucide-react';
|
||||
import './reusable.css';
|
||||
import '../../styles/styles.css';
|
||||
|
||||
@ -15,27 +15,30 @@ export function StatsTile({ tile, idx = 0 }: StatsTileProps) {
|
||||
|
||||
const lowerKey = String(tile.key).toLowerCase();
|
||||
|
||||
// Try to pick a relevant icon
|
||||
// Try to pick a relevant icon and color theme
|
||||
let Icon = BarChart2;
|
||||
if (lowerKey.includes('call') || lowerKey.includes('total')) Icon = Phone;
|
||||
if (lowerKey.includes('productive')) Icon = TrendingUp;
|
||||
if (lowerKey.includes('order') || lowerKey.includes('cart')) Icon = ShoppingCart;
|
||||
if (lowerKey.includes('bag')) Icon = ShoppingBag;
|
||||
if (lowerKey.includes('kg') || lowerKey.includes('weight')) Icon = Scale;
|
||||
if (lowerKey.includes('active')) Icon = Activity;
|
||||
let colorTheme = 'blue';
|
||||
|
||||
const isDanger = lowerKey.includes('no_order');
|
||||
if (lowerKey.includes('call') || lowerKey.includes('total')) { Icon = Phone; colorTheme = 'blue'; }
|
||||
if (lowerKey.includes('productive')) { Icon = TrendingUp; colorTheme = 'green'; }
|
||||
if (lowerKey.includes('order') || lowerKey.includes('cart')) { Icon = ShoppingCart; colorTheme = 'blue'; }
|
||||
if (lowerKey.includes('bag')) { Icon = ShoppingBag; colorTheme = 'green'; }
|
||||
if (lowerKey.includes('kg') || lowerKey.includes('weight')) { Icon = Scale; colorTheme = 'purple'; }
|
||||
if (lowerKey.includes('active')) { Icon = Activity; colorTheme = 'blue'; }
|
||||
if (lowerKey.includes('store')) { Icon = Store; colorTheme = 'blue'; }
|
||||
if (lowerKey.includes('area') || lowerKey.includes('region')) { Icon = Map; colorTheme = 'purple'; }
|
||||
|
||||
return (
|
||||
<div className={`z-stats-tile z-stats-tile--secondary ${isDanger ? 'z-stats-tile--danger' : ''}`}>
|
||||
<div className="z-stats-header">
|
||||
<span className={`z-stats-label`}>{displayLabel}</span>
|
||||
<Icon size={16} className={`z-stats-icon ${isDanger ? 'z-stats-icon--danger' : ''}`} />
|
||||
<div className={`z-stats-tile z-stats-tile--${colorTheme}`}>
|
||||
<div className="z-stats-icon-wrapper">
|
||||
<Icon size={26} className="z-stats-icon" strokeWidth={2.5} />
|
||||
</div>
|
||||
<div className="z-stats-content">
|
||||
<span className="z-stats-label">{displayLabel}</span>
|
||||
<p className="z-stats-value">
|
||||
{(tile.value as React.ReactNode) ?? "-"}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p className={`z-stats-value nums ${isDanger ? 'z-stats-value--danger' : ''}`}>
|
||||
{(tile.value as React.ReactNode) ?? "-"}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ export function Textarea({
|
||||
return (
|
||||
<label className={cn('flex flex-col gap-1.5 font-sans', disabled && 'cursor-not-allowed', className)}>
|
||||
{label && (
|
||||
<span className="text-sm font-medium text-muted">
|
||||
<span className="text-sm font-semibold text-slate-700">
|
||||
{label}
|
||||
{required && <span className="text-ruby-600"> *</span>}
|
||||
</span>
|
||||
|
||||
@ -17,99 +17,86 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* Base Tile */
|
||||
.z-stats-tile {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
border-radius: var(--z-border-radius-lg);
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
background: var(--z-bg-neutral-200);
|
||||
border-radius: var(--z-border-radius-lg, 12px);
|
||||
box-shadow: var(--block-shadow, 0 7px 7px rgba(0, 0, 0, 0.1));
|
||||
border: 1px solid var(--z-neutral-500);
|
||||
font-family: var(--font-sans, system-ui, -apple-system, sans-serif);
|
||||
}
|
||||
|
||||
.z-stats-tile:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.z-stats-icon-wrapper {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Color Themes */
|
||||
.z-stats-tile--blue .z-stats-icon-wrapper {
|
||||
background-color: #e0ebff;
|
||||
}
|
||||
|
||||
.z-stats-tile--blue .z-stats-icon {
|
||||
color: var(--z-text-primary-400, #0055ff);
|
||||
}
|
||||
|
||||
.z-stats-tile--green .z-stats-icon-wrapper {
|
||||
background-color: #dcfce7;
|
||||
}
|
||||
|
||||
.z-stats-tile--green .z-stats-icon {
|
||||
color: #00b050;
|
||||
/* adjusted for the green from the image */
|
||||
}
|
||||
|
||||
.z-stats-tile--purple .z-stats-icon-wrapper {
|
||||
background-color: #f3e8ff;
|
||||
}
|
||||
|
||||
.z-stats-tile--purple .z-stats-icon {
|
||||
color: #6a35ff;
|
||||
/* adjusted for purple from image */
|
||||
}
|
||||
|
||||
/* Content */
|
||||
.z-stats-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
transition: transform 0.2s ease;
|
||||
box-shadow: var(--block-shadow);
|
||||
font-family: var(--font-sans);
|
||||
}
|
||||
|
||||
/* Secondary Tile (White) */
|
||||
.z-stats-tile--secondary {
|
||||
background-color: var(--z-bg-neutral-100);
|
||||
border: 1px solid var(--z-border-neutral-300);
|
||||
border-left: 4px solid var(--z-text-primary-400);
|
||||
color: var(--z-text-neutral-900);
|
||||
}
|
||||
|
||||
.z-stats-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.z-stats-label {
|
||||
font-size: var(--z-font-size-xs);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
color: #8892a0;
|
||||
/* subtle gray */
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 80px;
|
||||
}
|
||||
|
||||
.z-stats-tile--secondary .z-stats-label {
|
||||
color: var(--z-text-neutral-500);
|
||||
}
|
||||
|
||||
.z-stats-tile--secondary .z-stats-label.z-stats-label--danger {
|
||||
color: var(--z-text-danger-400);
|
||||
}
|
||||
|
||||
.z-stats-tile--secondary .z-stats-icon {
|
||||
color: var(--z-text-success-400);
|
||||
}
|
||||
|
||||
.z-stats-tile--secondary .z-stats-icon.z-stats-icon--danger {
|
||||
color: var(--z-text-danger-400);
|
||||
letter-spacing: 0.04em;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.z-stats-value {
|
||||
font-size: 30px;
|
||||
font-size: 32px;
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
font-family: var(--font-numeric);
|
||||
}
|
||||
|
||||
.z-stats-tile--secondary .z-stats-value {
|
||||
color: var(--z-text-primary-400);
|
||||
}
|
||||
|
||||
.z-stats-tile--secondary .z-stats-value.z-stats-value--danger {
|
||||
color: var(--z-text-danger-400);
|
||||
}
|
||||
|
||||
.z-stats-tile--secondary.z-stats-tile--danger {
|
||||
border-left-color: var(--z-text-danger-400);
|
||||
}
|
||||
|
||||
.z-stats-footer {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.z-stats-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
border-radius: var(--z-border-radius-pill);
|
||||
}
|
||||
|
||||
.z-stats-tile--secondary .z-stats-badge {
|
||||
padding: 0;
|
||||
color: var(--z-text-success-400);
|
||||
text-transform: uppercase;
|
||||
color: var(--z-text-primary-400, #0055ff);
|
||||
font-family: var(--font-numeric, inherit);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
@ -27,7 +27,7 @@ export function ConsoleLayout() {
|
||||
|
||||
return (
|
||||
<div className="h-[100dvh] overflow-hidden bg-app flex flex-col">
|
||||
<header className="print:hidden sticky top-0 z-20 shrink-0 flex items-center justify-between gap-3 px-4 h-14 pt-[env(safe-area-inset-top)] top-navbar">
|
||||
<header className="print:hidden sticky top-0 z-20 shrink-0 flex items-center justify-between gap-3 px-4 h-14 pt-[env(safe-area-inset-top)] top-navbar shadow-md">
|
||||
<div className="flex items-center gap-3 flex-1">
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@ -156,9 +156,9 @@
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Sunrise focus ring on inputs/selects. */
|
||||
/* Primary focus ring on inputs/selects. */
|
||||
.focus-ring:focus-within {
|
||||
border-color: var(--sunrise-500);
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: var(--shadow-focus);
|
||||
}
|
||||
|
||||
@ -193,6 +193,7 @@
|
||||
|
||||
:root {
|
||||
--primary-color: #1d4ed8;
|
||||
--primary-color-300: #93c5fd;
|
||||
--secondary-color: #f9fafb;
|
||||
--font-color: #10182b;
|
||||
--font-family: "IBM Plex Sans", serif;
|
||||
|
||||
@ -97,7 +97,7 @@
|
||||
--action-primary-hover: var(--sunrise-600);
|
||||
--action-navy: var(--navy-900);
|
||||
--action-navy-hover: var(--navy-800);
|
||||
--focus-ring: rgba(242,107,58,0.45);
|
||||
--focus-ring: rgba(29,78,216,0.3); /* Matches primary-color #1d4ed8 with opacity */
|
||||
|
||||
/* Status */
|
||||
--status-success: var(--emerald-600);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user