feat(dashboard): added dashboard content and features (#7)
All checks were successful
CI / Format (push) Successful in 2s
CI / Clippy (push) Successful in 2m18s
CI / Security Audit (push) Successful in 1m40s
CI / Tests (push) Successful in 2m51s
CI / Deploy (push) Successful in 2s

Co-authored-by: Sharang Parnerkar <parnerkarsharang@gmail.com>
Reviewed-on: #7
This commit was merged in pull request #7.
This commit is contained in:
2026-02-19 19:23:06 +00:00
parent a588be306a
commit 5399afd748
20 changed files with 3111 additions and 131 deletions

View File

@@ -7,7 +7,12 @@ body {
padding: 0;
}
h1, h2, h3, h4, h5, h6 {
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'Space Grotesk', sans-serif;
}
@@ -509,11 +514,9 @@ h1, h2, h3, h4, h5, h6 {
margin: 0 auto 80px;
padding: 64px 48px;
text-align: center;
background: linear-gradient(
135deg,
rgba(145, 164, 210, 0.08),
rgba(109, 133, 198, 0.04)
);
background: linear-gradient(135deg,
rgba(145, 164, 210, 0.08),
rgba(109, 133, 198, 0.04));
border: 1px solid rgba(145, 164, 210, 0.15);
border-radius: 20px;
}
@@ -995,6 +998,8 @@ h1, h2, h3, h4, h5, h6 {
border-radius: 12px;
overflow: hidden;
transition: border-color 0.2s ease, transform 0.2s ease;
display: flex;
flex-direction: column;
}
.news-card:hover {
@@ -1002,14 +1007,26 @@ h1, h2, h3, h4, h5, h6 {
transform: translateY(-2px);
}
.news-card-thumb {
overflow: hidden;
height: 140px;
flex-shrink: 0;
}
.news-card-thumb img {
width: 100%;
height: 140px;
height: 100%;
object-fit: cover;
/* Hide alt text on broken images */
color: transparent;
font-size: 0;
}
.news-card-body {
padding: 20px;
flex: 1;
display: flex;
flex-direction: column;
}
.news-card-meta {
@@ -1027,13 +1044,35 @@ h1, h2, h3, h4, h5, h6 {
border-radius: 4px;
text-transform: uppercase;
letter-spacing: 0.05em;
/* Default badge color for any topic */
background-color: rgba(99, 132, 210, 0.15);
color: #91a4d2;
}
.news-badge--llm { background-color: rgba(99, 102, 241, 0.15); color: #818cf8; }
.news-badge--agents { background-color: rgba(168, 85, 247, 0.15); color: #c084fc; }
.news-badge--privacy { background-color: rgba(34, 197, 94, 0.15); color: #4ade80; }
.news-badge--infrastructure { background-color: rgba(234, 179, 8, 0.15); color: #facc15; }
.news-badge--open-source { background-color: rgba(236, 72, 153, 0.15); color: #f472b6; }
.news-badge--llm {
background-color: rgba(99, 102, 241, 0.15);
color: #818cf8;
}
.news-badge--agents {
background-color: rgba(168, 85, 247, 0.15);
color: #c084fc;
}
.news-badge--privacy {
background-color: rgba(34, 197, 94, 0.15);
color: #4ade80;
}
.news-badge--infrastructure {
background-color: rgba(234, 179, 8, 0.15);
color: #facc15;
}
.news-badge--open-source {
background-color: rgba(236, 72, 153, 0.15);
color: #f472b6;
}
.news-card-source {
font-size: 12px;
@@ -1069,6 +1108,487 @@ h1, h2, h3, h4, h5, h6 {
margin: 0;
}
.news-card--selected {
border-color: #91a4d2;
background-color: rgba(145, 164, 210, 0.08);
}
.news-card--no-thumb {
min-height: 200px;
}
.news-card--no-thumb .news-card-body {
text-align: center;
justify-content: center;
}
.news-card--no-thumb .news-card-meta {
justify-content: center;
}
.news-card {
cursor: pointer;
}
/* ===== Dashboard Split View ===== */
.dashboard-split {
display: flex;
gap: 24px;
min-height: 60vh;
}
.dashboard-full {
display: block;
}
/* ===== Dashboard With Sidebar ===== */
.dashboard-with-sidebar {
display: flex;
gap: 24px;
min-height: 60vh;
}
.dashboard-full-grid {
width: 100%;
}
.dashboard-left {
width: 40%;
min-width: 0;
overflow-y: auto;
max-height: 80vh;
}
.dashboard-right {
width: 60%;
min-width: 0;
position: sticky;
top: 24px;
align-self: flex-start;
max-height: 80vh;
overflow-y: auto;
}
.news-grid--compact {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
}
.dashboard-loading {
text-align: center;
padding: 24px;
color: #8892a8;
font-size: 14px;
}
/* ===== Topic Tabs ===== */
.topic-tab-wrapper {
display: inline-flex;
align-items: center;
gap: 2px;
}
.topic-remove {
background: none;
border: none;
color: #5a6478;
font-size: 12px;
cursor: pointer;
padding: 2px 4px;
border-radius: 4px;
transition: color 0.15s ease;
}
.topic-remove:hover {
color: #f87171;
}
.topic-add-btn {
padding: 6px 14px;
border-radius: 20px;
border: 1px dashed #2a2f3d;
background-color: transparent;
color: #5a6478;
font-size: 16px;
cursor: pointer;
transition: all 0.15s ease;
font-family: 'Inter', sans-serif;
line-height: 1;
}
.topic-add-btn:hover {
border-color: #91a4d2;
color: #91a4d2;
}
.topic-input-wrapper {
display: inline-flex;
align-items: center;
gap: 8px;
}
.topic-input {
padding: 5px 12px;
border-radius: 20px;
border: 1px solid #2a2f3d;
background-color: #1a1d26;
color: #e2e8f0;
font-size: 13px;
font-family: 'Inter', sans-serif;
outline: none;
width: 140px;
}
.topic-input:focus {
border-color: #91a4d2;
}
.topic-cancel-btn {
background: none;
border: none;
color: #5a6478;
font-size: 12px;
cursor: pointer;
}
.topic-cancel-btn:hover {
color: #e2e8f0;
}
/* ===== Settings Panel ===== */
.settings-toggle {
margin-left: auto;
}
.settings-panel {
background-color: #1a1d26;
border: 1px solid #2a2f3d;
border-radius: 12px;
padding: 20px;
margin-bottom: 24px;
}
.settings-panel-title {
font-size: 15px;
font-weight: 600;
color: #e2e8f0;
margin: 0 0 16px;
}
.settings-field {
margin-bottom: 12px;
}
.settings-field label {
display: block;
font-size: 12px;
color: #8892a8;
margin-bottom: 4px;
font-weight: 500;
}
.settings-input {
width: 100%;
max-width: 400px;
padding: 8px 12px;
border-radius: 8px;
border: 1px solid #2a2f3d;
background-color: #0f1116;
color: #e2e8f0;
font-size: 13px;
font-family: 'Inter', sans-serif;
outline: none;
}
.settings-input:focus {
border-color: #91a4d2;
}
.settings-hint {
background-color: rgba(234, 179, 8, 0.1);
border: 1px solid rgba(234, 179, 8, 0.3);
border-radius: 8px;
padding: 12px 16px;
margin-bottom: 16px;
font-size: 13px;
color: #facc15;
}
/* ===== Article Detail Panel ===== */
.article-detail-panel {
background-color: #1a1d26;
border: 1px solid #2a2f3d;
border-radius: 12px;
padding: 24px;
position: relative;
}
.article-detail-close {
position: absolute;
top: 16px;
right: 16px;
background: none;
border: 1px solid #2a2f3d;
color: #8892a8;
width: 32px;
height: 32px;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.15s ease;
}
.article-detail-close:hover {
border-color: #f87171;
color: #f87171;
}
.article-detail-content {
padding-right: 40px;
}
.article-detail-title {
font-size: 22px;
font-weight: 700;
color: #f1f5f9;
margin: 0 0 12px;
line-height: 1.3;
}
.article-detail-meta {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.article-detail-source {
font-size: 13px;
color: #8892a8;
display: inline-flex;
align-items: center;
gap: 6px;
}
.source-favicon {
width: 16px;
height: 16px;
border-radius: 2px;
flex-shrink: 0;
}
.article-detail-date {
font-size: 13px;
color: #5a6478;
}
.article-detail-body {
margin-bottom: 20px;
}
.article-detail-body p {
font-size: 14px;
line-height: 1.7;
color: #c8d0e0;
margin: 0;
}
.article-detail-link {
display: inline-block;
font-size: 13px;
color: #91a4d2;
text-decoration: none;
margin-bottom: 20px;
transition: color 0.15s ease;
}
.article-detail-link:hover {
color: #b4c4e8;
}
/* ---- AI Summary Bubble ---- */
.ai-summary-bubble {
margin-top: 20px;
background-color: rgba(145, 164, 210, 0.08);
border: 1px solid rgba(145, 164, 210, 0.18);
border-radius: 12px;
padding: 16px 18px;
position: relative;
}
.ai-summary-bubble-text {
font-size: 14px;
line-height: 1.65;
color: #c8d0e0;
margin: 0;
white-space: pre-wrap;
}
.ai-summary-bubble-label {
display: block;
font-size: 11px;
font-weight: 600;
color: #91a4d2;
margin-top: 12px;
text-transform: uppercase;
letter-spacing: 0.05em;
opacity: 0.6;
}
.ai-summary-bubble-loading {
display: flex;
align-items: center;
gap: 10px;
font-size: 14px;
color: #91a4d2;
font-style: italic;
}
/* Pulsing dots animation for loading states */
.ai-summary-dot-pulse {
display: flex;
gap: 4px;
}
.ai-summary-dot-pulse::before,
.ai-summary-dot-pulse::after,
.ai-summary-dot-pulse {
position: relative;
}
.ai-summary-dot-pulse::before,
.ai-summary-dot-pulse::after {
content: "";
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
background: #91a4d2;
animation: dotPulse 1.2s infinite ease-in-out;
}
.ai-summary-dot-pulse::after {
animation-delay: 0.4s;
}
@keyframes dotPulse {
0%,
80%,
100% {
opacity: 0.3;
transform: scale(0.8);
}
40% {
opacity: 1;
transform: scale(1);
}
}
/* ---- Follow-up Chat ---- */
.article-chat {
margin-top: 16px;
border-top: 1px solid #2a2f3d;
padding-top: 16px;
}
.article-chat-messages {
max-height: 300px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 12px;
padding-right: 4px;
}
.chat-msg {
max-width: 85%;
padding: 10px 14px;
border-radius: 12px;
font-size: 14px;
line-height: 1.55;
}
.chat-msg p {
margin: 0;
white-space: pre-wrap;
}
.chat-msg--user {
align-self: flex-end;
background: rgba(99, 132, 210, 0.2);
border: 1px solid rgba(99, 132, 210, 0.3);
color: #d0d8ee;
border-bottom-right-radius: 4px;
}
.chat-msg--assistant {
align-self: flex-start;
background: rgba(145, 164, 210, 0.08);
border: 1px solid rgba(145, 164, 210, 0.15);
color: #c8d0e0;
border-bottom-left-radius: 4px;
}
.chat-msg--typing {
padding: 12px 16px;
}
.article-chat-input {
display: flex;
gap: 8px;
}
.article-chat-textbox {
flex: 1;
background: #1a1e2e;
border: 1px solid #2a2f3d;
border-radius: 8px;
padding: 10px 14px;
font-size: 14px;
color: #c8d0e0;
outline: none;
transition: border-color 0.2s;
}
.article-chat-textbox:focus {
border-color: #6384d2;
}
.article-chat-textbox:disabled {
opacity: 0.5;
}
.article-chat-send {
background: #6384d2;
color: #fff;
border: none;
border-radius: 8px;
padding: 10px 18px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: background 0.2s;
white-space: nowrap;
}
.article-chat-send:hover:not(:disabled) {
background: #5270b8;
}
.article-chat-send:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* ===== Providers Page ===== */
.providers-page {
max-width: 960px;
@@ -1367,9 +1887,17 @@ h1, h2, h3, h4, h5, h6 {
border-radius: 50%;
}
.tool-status--active { background-color: #4ade80; }
.tool-status--inactive { background-color: #5a6478; }
.tool-status--error { background-color: #f87171; }
.tool-status--active {
background-color: #4ade80;
}
.tool-status--inactive {
background-color: #5a6478;
}
.tool-status--error {
background-color: #f87171;
}
.tool-card-name {
font-size: 16px;
@@ -1571,8 +2099,13 @@ h1, h2, h3, h4, h5, h6 {
font-weight: 500;
}
.analytics-stat-change--up { color: #4ade80; }
.analytics-stat-change--down { color: #f87171; }
.analytics-stat-change--up {
color: #4ade80;
}
.analytics-stat-change--down {
color: #f87171;
}
/* ===== Pricing Page ===== */
.pricing-page {
@@ -1790,8 +2323,107 @@ h1, h2, h3, h4, h5, h6 {
margin-top: 24px;
}
/* ===== Dashboard Sidebar ===== */
.dashboard-sidebar {
width: 30%;
min-width: 240px;
max-width: 320px;
position: sticky;
top: 24px;
align-self: flex-start;
max-height: 80vh;
overflow-y: auto;
border-left: 1px solid #1e222d;
padding-left: 24px;
display: flex;
flex-direction: column;
gap: 24px;
}
.sidebar-section {
display: flex;
flex-direction: column;
gap: 10px;
}
.sidebar-section-title {
font-size: 12px;
font-weight: 600;
color: #5a6478;
text-transform: uppercase;
letter-spacing: 0.05em;
margin: 0;
}
.sidebar-status-row {
display: flex;
align-items: center;
gap: 8px;
}
.sidebar-status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
flex-shrink: 0;
}
.sidebar-status-dot--online {
background-color: #4ade80;
box-shadow: 0 0 6px rgba(74, 222, 128, 0.4);
}
.sidebar-status-dot--offline {
background-color: #f87171;
box-shadow: 0 0 6px rgba(248, 113, 113, 0.4);
}
.sidebar-status-label {
font-size: 13px;
color: #e2e8f0;
font-weight: 500;
}
.sidebar-model-list {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.sidebar-model-tag {
display: inline-block;
font-size: 11px;
font-weight: 500;
padding: 3px 10px;
border-radius: 12px;
background-color: rgba(145, 164, 210, 0.1);
color: #91a4d2;
border: 1px solid rgba(145, 164, 210, 0.2);
}
.sidebar-topic-link {
display: block;
width: 100%;
text-align: left;
background: none;
border: none;
padding: 6px 10px;
border-radius: 6px;
font-size: 13px;
font-family: 'Inter', sans-serif;
color: #8892a8;
cursor: pointer;
transition: background-color 0.15s ease, color 0.15s ease;
}
.sidebar-topic-link:hover {
background-color: rgba(145, 164, 210, 0.08);
color: #e2e8f0;
}
/* ===== Responsive: Dashboard Pages ===== */
@media (max-width: 1024px) {
.news-grid,
.tools-grid,
.pricing-grid {
@@ -1809,15 +2441,48 @@ h1, h2, h3, h4, h5, h6 {
.org-stats-bar {
flex-wrap: wrap;
}
.dashboard-sidebar {
display: none;
}
.dashboard-with-sidebar {
display: block;
}
.dashboard-split {
flex-direction: column;
}
.dashboard-left {
width: 100%;
max-height: none;
overflow-y: visible;
}
.dashboard-right {
width: 100%;
position: static;
max-height: none;
}
.news-grid--compact {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.news-grid,
.tools-grid,
.pricing-grid {
grid-template-columns: 1fr;
}
.news-grid--compact {
grid-template-columns: 1fr;
}
.chat-page {
flex-direction: column;
height: auto;
@@ -1848,4 +2513,4 @@ h1, h2, h3, h4, h5, h6 {
min-width: unset;
margin: 16px;
}
}
}

17
assets/manifest.json Normal file
View File

@@ -0,0 +1,17 @@
{
"name": "CERTifAI Dashboard",
"short_name": "CERTifAI",
"description": "Self-hosted GenAI infrastructure management dashboard",
"start_url": "/dashboard",
"display": "standalone",
"background_color": "#0f1117",
"theme_color": "#4B3FE0",
"icons": [
{
"src": "/assets/logo.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "any maskable"
}
]
}

67
assets/sw.js Normal file
View File

@@ -0,0 +1,67 @@
// CERTifAI Service Worker — network-first with offline fallback cache.
// Static assets (CSS, JS, WASM, fonts) use cache-first for speed.
// API and navigation requests always try the network first.
const CACHE_NAME = "certifai-v1";
// Pre-cache the app shell on install
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) =>
cache.addAll([
"/",
"/dashboard",
"/assets/logo.svg",
"/assets/favicon.ico",
])
)
);
self.skipWaiting();
});
// Clean up old caches on activate
self.addEventListener("activate", (event) => {
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(
keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k))
)
)
);
self.clients.claim();
});
self.addEventListener("fetch", (event) => {
const url = new URL(event.request.url);
// Skip non-GET and API requests (let them go straight to network)
if (event.request.method !== "GET" || url.pathname.startsWith("/api/")) {
return;
}
// Cache-first for static assets (hashed filenames make this safe)
const isStatic = /\.(js|wasm|css|ico|svg|png|jpg|woff2?)(\?|$)/.test(url.pathname);
if (isStatic) {
event.respondWith(
caches.match(event.request).then((cached) =>
cached || fetch(event.request).then((resp) => {
const clone = resp.clone();
caches.open(CACHE_NAME).then((c) => c.put(event.request, clone));
return resp;
})
)
);
return;
}
// Network-first for navigation / HTML
event.respondWith(
fetch(event.request)
.then((resp) => {
const clone = resp.clone();
caches.open(CACHE_NAME).then((c) => c.put(event.request, clone));
return resp;
})
.catch(() => caches.match(event.request))
);
});

View File

@@ -162,6 +162,147 @@
}
}
@layer utilities {
.modal {
@layer daisyui.l1.l2.l3 {
pointer-events: none;
visibility: hidden;
position: fixed;
inset: calc(0.25rem * 0);
margin: calc(0.25rem * 0);
display: grid;
height: 100%;
max-height: none;
width: 100%;
max-width: none;
align-items: center;
justify-items: center;
background-color: transparent;
padding: calc(0.25rem * 0);
color: inherit;
transition: visibility 0.3s allow-discrete, background-color 0.3s ease-out, opacity 0.1s ease-out;
overflow: clip;
overscroll-behavior: contain;
z-index: 999;
scrollbar-gutter: auto;
&::backdrop {
display: none;
}
}
@layer daisyui.l1.l2 {
&.modal-open, &[open], &:target, .modal-toggle:checked + & {
pointer-events: auto;
visibility: visible;
opacity: 100%;
transition: visibility 0s allow-discrete, background-color 0.3s ease-out, opacity 0.1s ease-out;
background-color: oklch(0% 0 0/ 0.4);
.modal-box {
translate: 0 0;
scale: 1;
opacity: 1;
}
:root:has(&) {
--page-has-backdrop: 1;
--page-overflow: hidden;
--page-scroll-bg: var(--page-scroll-bg-on);
--page-scroll-gutter: stable;
--page-scroll-transition: var(--page-scroll-transition-on);
animation: set-page-has-scroll forwards;
animation-timeline: scroll();
}
}
@starting-style {
&.modal-open, &[open], &:target, .modal-toggle:checked + & {
opacity: 0%;
}
}
}
}
.tab {
@layer daisyui.l1.l2.l3 {
position: relative;
display: inline-flex;
cursor: pointer;
appearance: none;
flex-wrap: wrap;
align-items: center;
justify-content: center;
text-align: center;
webkit-user-select: none;
user-select: none;
&:hover {
@media (hover: hover) {
color: var(--color-base-content);
}
}
--tab-p: 0.75rem;
--tab-bg: var(--color-base-100);
--tab-border-color: var(--color-base-300);
--tab-radius-ss: 0;
--tab-radius-se: 0;
--tab-radius-es: 0;
--tab-radius-ee: 0;
--tab-order: 0;
--tab-radius-min: calc(0.75rem - var(--border));
--tab-radius-limit: min(var(--radius-field), var(--tab-radius-min));
--tab-radius-grad: #0000 calc(69% - var(--border)),
var(--tab-border-color) calc(69% - var(--border) + 0.25px),
var(--tab-border-color) 69%,
var(--tab-bg) calc(69% + 0.25px);
border-color: #0000;
order: var(--tab-order);
height: var(--tab-height);
font-size: 0.875rem;
padding-inline: var(--tab-p);
&:is(input[type="radio"]) {
min-width: fit-content;
&:after {
--tw-content: attr(aria-label);
content: var(--tw-content);
}
}
&:is(label) {
position: relative;
input {
position: absolute;
inset: calc(0.25rem * 0);
cursor: pointer;
appearance: none;
opacity: 0%;
}
}
&:checked, &:is(label:has(:checked)), &:is(.tab-active, [aria-selected="true"], [aria-current="true"], [aria-current="page"]) {
& + .tab-content {
display: block;
}
}
&:not( :checked, label:has(:checked), :hover, .tab-active, [aria-selected="true"], [aria-current="true"], [aria-current="page"] ) {
color: var(--color-base-content);
@supports (color: color-mix(in lab, red, red)) {
color: color-mix(in oklab, var(--color-base-content) 50%, transparent);
}
}
&:not(input):empty {
flex-grow: 1;
cursor: default;
}
&:focus {
--tw-outline-style: none;
outline-style: none;
@media (forced-colors: active) {
outline: 2px solid transparent;
outline-offset: 2px;
}
}
&:focus-visible, &:is(label:has(:checked:focus-visible)) {
outline: 2px solid currentColor;
outline-offset: -5px;
}
&[disabled] {
pointer-events: none;
opacity: 40%;
}
}
}
.btn {
:where(&) {
@layer daisyui.l1.l2.l3 {
@@ -314,6 +455,65 @@
.visible {
visibility: visible;
}
.list {
@layer daisyui.l1.l2.l3 {
display: flex;
flex-direction: column;
font-size: 0.875rem;
.list-row {
--list-grid-cols: minmax(0, auto) 1fr;
position: relative;
display: grid;
grid-auto-flow: column;
gap: calc(0.25rem * 4);
border-radius: var(--radius-box);
padding: calc(0.25rem * 4);
word-break: break-word;
grid-template-columns: var(--list-grid-cols);
}
& > :not(:last-child) {
&.list-row, .list-row {
&:after {
content: "";
border-bottom: var(--border) solid;
inset-inline: var(--radius-box);
position: absolute;
bottom: calc(0.25rem * 0);
border-color: var(--color-base-content);
@supports (color: color-mix(in lab, red, red)) {
border-color: color-mix(in oklab, var(--color-base-content) 5%, transparent);
}
}
}
}
}
@layer daisyui.l1.l2 {
.list-row {
&:has(.list-col-grow:nth-child(1)) {
--list-grid-cols: 1fr;
}
&:has(.list-col-grow:nth-child(2)) {
--list-grid-cols: minmax(0, auto) 1fr;
}
&:has(.list-col-grow:nth-child(3)) {
--list-grid-cols: minmax(0, auto) minmax(0, auto) 1fr;
}
&:has(.list-col-grow:nth-child(4)) {
--list-grid-cols: minmax(0, auto) minmax(0, auto) minmax(0, auto) 1fr;
}
&:has(.list-col-grow:nth-child(5)) {
--list-grid-cols: minmax(0, auto) minmax(0, auto) minmax(0, auto) minmax(0, auto) 1fr;
}
&:has(.list-col-grow:nth-child(6)) {
--list-grid-cols: minmax(0, auto) minmax(0, auto) minmax(0, auto) minmax(0, auto)
minmax(0, auto) 1fr;
}
> * {
grid-row-start: 1;
}
}
}
}
.toggle {
@layer daisyui.l1.l2.l3 {
border: var(--border) solid currentColor;
@@ -589,6 +789,75 @@
}
}
}
.table {
@layer daisyui.l1.l2.l3 {
font-size: 0.875rem;
position: relative;
width: 100%;
border-collapse: separate;
--tw-border-spacing-x: calc(0.25rem * 0);
--tw-border-spacing-y: calc(0.25rem * 0);
border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y);
border-radius: var(--radius-box);
text-align: left;
&:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *) {
text-align: right;
}
tr.row-hover {
&, &:nth-child(even) {
&:hover {
@media (hover: hover) {
background-color: var(--color-base-200);
}
}
}
}
:where(th, td) {
padding-inline: calc(0.25rem * 4);
padding-block: calc(0.25rem * 3);
vertical-align: middle;
}
:where(thead, tfoot) {
white-space: nowrap;
color: var(--color-base-content);
@supports (color: color-mix(in lab, red, red)) {
color: color-mix(in oklab, var(--color-base-content) 60%, transparent);
}
font-size: 0.875rem;
font-weight: 600;
}
:where(tfoot tr:first-child :is(td, th)) {
border-top: var(--border) solid var(--color-base-content);
@supports (color: color-mix(in lab, red, red)) {
border-top: var(--border) solid color-mix(in oklch, var(--color-base-content) 5%, #0000);
}
}
:where(.table-pin-rows thead tr) {
position: sticky;
top: calc(0.25rem * 0);
z-index: 1;
background-color: var(--color-base-100);
}
:where(.table-pin-rows tfoot tr) {
position: sticky;
bottom: calc(0.25rem * 0);
z-index: 1;
background-color: var(--color-base-100);
}
:where(.table-pin-cols tr th) {
position: sticky;
right: calc(0.25rem * 0);
left: calc(0.25rem * 0);
background-color: var(--color-base-100);
}
:where(thead tr :is(td, th), tbody tr:not(:last-child) :is(td, th)) {
border-bottom: var(--border) solid var(--color-base-content);
@supports (color: color-mix(in lab, red, red)) {
border-bottom: var(--border) solid color-mix(in oklch, var(--color-base-content) 5%, #0000);
}
}
}
}
.steps {
@layer daisyui.l1.l2.l3 {
display: inline-grid;
@@ -699,6 +968,34 @@
}
}
}
.chat-bubble {
@layer daisyui.l1.l2.l3 {
position: relative;
display: block;
width: fit-content;
border-radius: var(--radius-field);
background-color: var(--color-base-300);
padding-inline: calc(0.25rem * 4);
padding-block: calc(0.25rem * 2);
color: var(--color-base-content);
grid-row-end: 3;
min-height: 2rem;
min-width: 2.5rem;
max-width: 90%;
&:before {
position: absolute;
bottom: calc(0.25rem * 0);
height: calc(0.25rem * 3);
width: calc(0.25rem * 3);
background-color: inherit;
content: "";
mask-repeat: no-repeat;
mask-image: var(--mask-chat);
mask-position: 0px -1px;
mask-size: 0.8125rem;
}
}
}
.select {
@layer daisyui.l1.l2.l3 {
border: var(--border) solid #0000;
@@ -934,6 +1231,15 @@
}
}
}
.stats {
@layer daisyui.l1.l2.l3 {
position: relative;
display: inline-grid;
grid-auto-flow: column;
overflow-x: auto;
border-radius: var(--radius-box);
}
}
.progress {
@layer daisyui.l1.l2.l3 {
position: relative;
@@ -999,6 +1305,76 @@
.end {
inset-inline-end: var(--spacing);
}
.join {
display: inline-flex;
align-items: stretch;
--join-ss: 0;
--join-se: 0;
--join-es: 0;
--join-ee: 0;
:where(.join-item) {
border-start-start-radius: var(--join-ss, 0);
border-start-end-radius: var(--join-se, 0);
border-end-start-radius: var(--join-es, 0);
border-end-end-radius: var(--join-ee, 0);
* {
--join-ss: var(--radius-field);
--join-se: var(--radius-field);
--join-es: var(--radius-field);
--join-ee: var(--radius-field);
}
}
> .join-item:where(:first-child) {
--join-ss: var(--radius-field);
--join-se: 0;
--join-es: var(--radius-field);
--join-ee: 0;
}
:first-child:not(:last-child) {
:where(.join-item) {
--join-ss: var(--radius-field);
--join-se: 0;
--join-es: var(--radius-field);
--join-ee: 0;
}
}
> .join-item:where(:last-child) {
--join-ss: 0;
--join-se: var(--radius-field);
--join-es: 0;
--join-ee: var(--radius-field);
}
:last-child:not(:first-child) {
:where(.join-item) {
--join-ss: 0;
--join-se: var(--radius-field);
--join-es: 0;
--join-ee: var(--radius-field);
}
}
> .join-item:where(:only-child) {
--join-ss: var(--radius-field);
--join-se: var(--radius-field);
--join-es: var(--radius-field);
--join-ee: var(--radius-field);
}
:only-child {
:where(.join-item) {
--join-ss: var(--radius-field);
--join-se: var(--radius-field);
--join-es: var(--radius-field);
--join-ee: var(--radius-field);
}
}
> :where(:focus, :has(:focus)) {
z-index: 1;
}
@media (hover: hover) {
> :where(.btn:hover, :has(.btn:hover)) {
isolation: isolate;
}
}
}
.hero-content {
@layer daisyui.l1.l2.l3 {
isolation: isolate;
@@ -1122,6 +1498,51 @@
max-width: 96rem;
}
}
.filter {
@layer daisyui.l1.l2.l3 {
display: flex;
flex-wrap: wrap;
input[type="radio"] {
width: auto;
}
input {
overflow: hidden;
opacity: 100%;
scale: 1;
transition: margin 0.1s, opacity 0.3s, padding 0.3s, border-width 0.1s;
&:not(:last-child) {
margin-inline-end: calc(0.25rem * 1);
}
&.filter-reset {
aspect-ratio: 1 / 1;
&::after {
--tw-content: "×";
content: var(--tw-content);
}
}
}
&:not(:has(input:checked:not(.filter-reset))) {
.filter-reset, input[type="reset"] {
scale: 0;
border-width: 0;
margin-inline: calc(0.25rem * 0);
width: calc(0.25rem * 0);
padding-inline: calc(0.25rem * 0);
opacity: 0%;
}
}
&:has(input:checked:not(.filter-reset)) {
input:not(:checked, .filter-reset, input[type="reset"]) {
scale: 0;
border-width: 0;
margin-inline: calc(0.25rem * 0);
width: calc(0.25rem * 0);
padding-inline: calc(0.25rem * 0);
opacity: 0%;
}
}
}
}
.label {
@layer daisyui.l1.l2.l3 {
display: inline-flex;
@@ -1208,6 +1629,17 @@
padding-inline: calc(var(--size) / 2 - var(--border));
}
}
.tabs {
@layer daisyui.l1.l2.l3 {
display: flex;
flex-wrap: wrap;
--tabs-height: auto;
--tabs-direction: row;
--tab-height: calc(var(--size-field, 0.25rem) * 10);
height: var(--tabs-height);
flex-direction: var(--tabs-direction);
}
}
.footer {
@layer daisyui.l1.l2.l3 {
display: grid;
@@ -1233,6 +1665,15 @@
}
}
}
.chat {
@layer daisyui.l1.l2.l3 {
display: grid;
grid-auto-rows: min-content;
column-gap: calc(0.25rem * 3);
padding-block: calc(0.25rem * 1);
--mask-chat: url("data:image/svg+xml,%3csvg width='13' height='13' xmlns='http://www.w3.org/2000/svg'%3e%3cpath fill='black' d='M0 11.5004C0 13.0004 2 13.0004 2 13.0004H12H13V0.00036329L12.5 0C12.5 0 11.977 2.09572 11.8581 2.50033C11.6075 3.35237 10.9149 4.22374 9 5.50036C6 7.50036 0 10.0004 0 11.5004Z'/%3e%3c/svg%3e");
}
}
.card-title {
@layer daisyui.l1.l2.l3 {
display: flex;
@@ -1242,12 +1683,21 @@
font-weight: 600;
}
}
.block {
display: block;
}
.grid {
display: grid;
}
.hidden {
display: none;
}
.inline {
display: inline;
}
.table {
display: table;
}
.transform {
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
}
@@ -1311,6 +1761,9 @@
}
}
}
.filter {
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
}
.btn-outline {
@layer daisyui.l1 {
&:not( .btn-active, :hover, :active:focus, :focus-visible, input:checked:not(.filter .btn), :disabled, [disabled], .btn-disabled ) {
@@ -1351,6 +1804,12 @@
--btn-fg: var(--color-primary-content);
}
}
.btn-secondary {
@layer daisyui.l1.l2.l3 {
--btn-color: var(--color-secondary);
--btn-fg: var(--color-secondary-content);
}
}
}
@layer base {
:where(:root),:root:has(input.theme-controller[value=light]:checked),[data-theme=light] {
@@ -1724,6 +2183,59 @@
inherits: false;
initial-value: solid;
}
@property --tw-blur {
syntax: "*";
inherits: false;
}
@property --tw-brightness {
syntax: "*";
inherits: false;
}
@property --tw-contrast {
syntax: "*";
inherits: false;
}
@property --tw-grayscale {
syntax: "*";
inherits: false;
}
@property --tw-hue-rotate {
syntax: "*";
inherits: false;
}
@property --tw-invert {
syntax: "*";
inherits: false;
}
@property --tw-opacity {
syntax: "*";
inherits: false;
}
@property --tw-saturate {
syntax: "*";
inherits: false;
}
@property --tw-sepia {
syntax: "*";
inherits: false;
}
@property --tw-drop-shadow {
syntax: "*";
inherits: false;
}
@property --tw-drop-shadow-color {
syntax: "*";
inherits: false;
}
@property --tw-drop-shadow-alpha {
syntax: "<percentage>";
inherits: false;
initial-value: 100%;
}
@property --tw-drop-shadow-size {
syntax: "*";
inherits: false;
}
@layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop {
@@ -1733,6 +2245,19 @@
--tw-skew-x: initial;
--tw-skew-y: initial;
--tw-outline-style: solid;
--tw-blur: initial;
--tw-brightness: initial;
--tw-contrast: initial;
--tw-grayscale: initial;
--tw-hue-rotate: initial;
--tw-invert: initial;
--tw-opacity: initial;
--tw-saturate: initial;
--tw-sepia: initial;
--tw-drop-shadow: initial;
--tw-drop-shadow-color: initial;
--tw-drop-shadow-alpha: 100%;
--tw-drop-shadow-size: initial;
}
}
}