Calendar/wwwroot/css/calendar-layout-css.css
Janus Knudsen 36ac8d18ab Implements native scrollbars with styling
Replaces custom scrollbar implementation with native scrollbars for better performance and accessibility.

Adds configuration options for scrollbar styling, including width, color, track color, hover color, and border radius.

Synchronizes week header and time axis scrolling with the scrollable content.
2025-08-05 23:03:08 +02:00

378 lines
No EOL
8.9 KiB
CSS

/* styles/layout.css - POC Structure Implementation */
/* Calendar wrapper container - full viewport */
.calendar-wrapper {
width: 100vw;
height: 100vh;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
box-sizing: border-box;
overflow: hidden;
}
/* Main calendar container - full height */
swp-calendar {
display: grid;
grid-template-rows: auto 1fr;
height: 100vh;
width: 100%;
background: var(--color-background);
position: relative;
overflow: hidden;
}
/* Navigation bar layout */
swp-calendar-nav {
display: grid;
grid-template-columns: auto 1fr auto auto;
align-items: center;
gap: 20px;
padding: 12px 16px;
background: var(--color-background);
border-bottom: 1px solid var(--color-border);
box-shadow: var(--shadow-sm);
}
/* Calendar container grid - POC structure */
swp-calendar-container {
display: grid;
grid-template-columns: 60px 1fr;
grid-template-rows: auto 1fr;
height: 100%;
overflow: hidden;
position: relative;
}
/* Header spacer for time axis alignment */
swp-header-spacer {
grid-column: 1;
grid-row: 1;
height: calc(var(--header-height) + var(--all-day-row-height)); /* Dynamic height including all-day events */
background: var(--color-surface);
border-right: 1px solid var(--color-border);
border-bottom: 1px solid var(--color-border);
z-index: 5; /* Higher than time-axis to cover it when scrolling */
position: relative;
transition: height 300ms ease; /* Smooth height transitions */
}
/* Week container for sliding */
swp-week-container {
grid-column: 2;
grid-row: 1 / 3;
display: grid;
grid-template-rows: auto 1fr;
position: relative;
width: 100%;
transition: transform 400ms cubic-bezier(0.4, 0, 0.2, 1);
overflow: hidden;
}
/* Time axis */
swp-time-axis {
grid-column: 1;
grid-row: 2;
background: var(--color-surface);
border-right: 1px solid var(--color-border);
position: relative;
left: 0;
z-index: 3; /* Lower than header elements so it scrolls behind them */
width: 60px;
overflow: hidden;
height: 100%;
}
/* Time axis content that scrolls */
swp-time-axis-content {
display: flex;
flex-direction: column;
position: relative;
}
swp-hour-marker {
height: var(--hour-height);
padding: 0 8px 8px 8px;
font-size: 0.75rem;
color: var(--color-text-secondary);
display: flex;
align-items: flex-start;
position: relative;
}
swp-hour-marker::before {
content: '';
position: absolute;
top: -1px;
left: 50px;
width: calc(100vw - 60px); /* Full viewport width minus time-axis width */
height: 1px;
background: var(--color-hour-line);
pointer-events: none;
z-index: 2; /* Ensure it appears above other elements */
}
/* Add hour lines to time-grid as background */
swp-time-grid::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
min-width: calc(var(--week-days) * var(--day-column-min-width)); /* Dynamic width like swp-grid-lines */
background-image: repeating-linear-gradient(
to bottom,
transparent,
transparent calc(var(--hour-height) - 1px),
var(--color-hour-line) calc(var(--hour-height) - 1px),
var(--color-hour-line) var(--hour-height)
);
pointer-events: none;
z-index: 1;
}
/* Week header - dynamic height based on content */
swp-week-header {
display: grid;
grid-template-columns: repeat(7, minmax(var(--day-column-min-width), 1fr));
grid-template-rows: var(--header-height) auto; /* Row 1: use CSS variable, Row 2: auto-sized for all-day events */
min-width: calc(var(--week-days) * var(--day-column-min-width)); /* Dynamic width */
background: var(--color-surface);
border-bottom: 1px solid var(--color-border);
position: sticky;
top: 0;
z-index: 3; /* Lower than header-spacer so it slides under during horizontal scroll */
height: calc(var(--header-height) + var(--all-day-row-height)); /* Same calculation as spacers */
}
swp-day-header {
padding: 12px;
text-align: center;
border-right: 1px solid var(--color-grid-line);
border-bottom: 1px solid var(--color-grid-line);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
swp-day-header:last-child {
border-right: none;
}
swp-day-name {
display: block;
font-weight: 500;
font-size: 0.875rem;
color: var(--color-text-secondary);
}
swp-day-date {
display: block;
font-size: 1.25rem;
font-weight: 600;
margin-top: 4px;
}
swp-day-header[data-today="true"] swp-day-date {
color: var(--color-primary);
background: rgba(33, 150, 243, 0.1);
border-radius: 50%;
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
margin: 4px auto 0;
}
/* All-day events in row 2 */
swp-allday-event {
grid-row: 2; /* Row 2 only */
height: calc(var(--all-day-row-height) - 3px); /* Dynamic height minus margin */
background: #ff9800; /* Default orange background */
display: flex;
align-items: center;
justify-content: flex-start;
color: #fff;
font-size: 0.75rem;
padding: 2px 4px;
margin: 1px;
border-radius: 3px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
border-right: 1px solid rgba(0, 0, 0, 0.1);
}
swp-allday-event:last-child {
border-right: none; /* Remove border from last all-day event */
}
/* Scrollable content */
swp-scrollable-content {
overflow-y: auto;
overflow-x: auto;
scroll-behavior: smooth;
position: relative;
display: grid;
/* Height and width will be set dynamically by ScrollManager via ResizeObserver */
}
/* Style native scrollbars for Webkit browsers (Chrome, Safari, Edge) */
swp-scrollable-content::-webkit-scrollbar {
width: var(--scrollbar-width, 12px);
height: var(--scrollbar-width, 12px);
}
swp-scrollable-content::-webkit-scrollbar-track {
background: var(--scrollbar-track-color, #f0f0f0);
}
swp-scrollable-content::-webkit-scrollbar-thumb {
background: var(--scrollbar-color, #666);
border-radius: var(--scrollbar-border-radius, 6px);
}
swp-scrollable-content::-webkit-scrollbar-thumb:hover {
background: var(--scrollbar-hover-color, #333);
}
/* Style native scrollbars for Firefox */
swp-scrollable-content {
scrollbar-width: auto; /* Let it use the webkit width */
scrollbar-color: var(--scrollbar-color, #666) var(--scrollbar-track-color, #f0f0f0);
}
/* Fit to width mode - disable horizontal scroll */
swp-calendar[data-fit-to-width="true"] swp-scrollable-content {
overflow-x: hidden;
}
/* Time grid */
swp-time-grid {
position: relative;
height: calc((var(--day-end-hour) - var(--day-start-hour)) * var(--hour-height));
}
swp-time-grid::before {
content: '';
position: absolute;
top: calc((var(--work-start-hour) - var(--day-start-hour)) * var(--hour-height));
height: calc((var(--work-end-hour) - var(--work-start-hour)) * var(--hour-height));
left: 0;
right: 0;
background: var(--color-work-hours);
min-width: calc(var(--week-days) * var(--day-column-min-width));
pointer-events: none;
}
/* Grid lines */
swp-grid-lines {
position: absolute;
top: 0px;
left: 0;
right: 0;
bottom: 0;
min-width: calc(var(--week-days) * var(--day-column-min-width)); /* Dynamic width */
pointer-events: none;
z-index: var(--z-grid);
background-image: repeating-linear-gradient(
to bottom,
transparent,
transparent calc(var(--hour-height) / 4 - 1px),
var(--color-grid-line-light) calc(var(--hour-height) / 4 - 1px),
var(--color-grid-line-light) calc(var(--hour-height) / 4)
);
}
/* Day columns */
swp-day-columns {
position: absolute;
inset: 0;
display: grid;
grid-template-columns: repeat(7, minmax(var(--day-column-min-width), 1fr));
min-width: calc(var(--week-days) * var(--day-column-min-width)); /* Dynamic width */
}
swp-day-column {
position: relative;
border-right: 1px solid var(--color-grid-line);
min-width: var(--day-column-min-width);
}
swp-day-column:last-child {
border-right: none;
}
swp-events-layer {
position: absolute;
inset: 0;
display: block;
z-index: var(--z-event);
pointer-events: none; /* Allow clicks to pass through to day column */
}
swp-event {
pointer-events: auto;
}
/* Current time indicator */
swp-current-time-indicator {
position: absolute;
left: 0;
right: 0;
height: 2px;
background: var(--color-current-time);
pointer-events: none;
z-index: var(--z-current-time);
/* Time label */
&::before {
content: attr(data-time);
position: absolute;
left: -55px;
top: -10px;
background: var(--color-current-time);
color: white;
padding: 2px 6px;
font-size: 0.75rem;
border-radius: 3px;
white-space: nowrap;
}
/* Animated dot */
&::after {
content: '';
position: absolute;
right: -4px;
top: -4px;
width: 10px;
height: 10px;
background: var(--color-current-time);
border-radius: 50%;
box-shadow: 0 0 0 2px rgba(255, 0, 0, 0.3);
}
}
/* Week navigation animations - simplified */
swp-calendar-container.week-transition {
transition: opacity 300ms ease;
}
swp-calendar-container.week-transition-out {
opacity: 0.5;
}