Removes redundant state tracking for all-day event layouts Shifts from maintaining internal layout state to reading directly from DOM elements Simplifies event handling and updates by using DOM as the source of truth Improves performance by reducing unnecessary state management
637 lines
No EOL
14 KiB
CSS
637 lines
No EOL
14 KiB
CSS
/* styles/layout.css - POC Structure Implementation with CSS Nesting */
|
|
|
|
/* 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;
|
|
|
|
/* Fit to width mode - disable horizontal scroll */
|
|
&[data-fit-to-width="true"] swp-scrollable-content {
|
|
overflow-x: 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;
|
|
|
|
/* Week navigation animations */
|
|
&.week-transition {
|
|
transition: opacity 300ms ease;
|
|
|
|
&-out {
|
|
opacity: 0.5;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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));
|
|
background: var(--color-surface);
|
|
border-right: 1px solid var(--color-border);
|
|
border-bottom: 1px solid var(--color-border);
|
|
z-index: 5;
|
|
position: relative;
|
|
}
|
|
|
|
/* All-day chevron button */
|
|
.allday-chevron {
|
|
position: absolute;
|
|
bottom: 2px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
padding: 4px 8px;
|
|
color: #666;
|
|
transition: transform 0.3s ease, color 0.2s ease;
|
|
border-radius: 4px;
|
|
|
|
&:hover {
|
|
color: #000;
|
|
background-color: rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
&.collapsed {
|
|
transform: translateX(-50%) rotate(0deg);
|
|
}
|
|
|
|
&.expanded {
|
|
transform: translateX(-50%) rotate(180deg);
|
|
}
|
|
|
|
svg {
|
|
display: block;
|
|
width: 12px;
|
|
height: 8px;
|
|
}
|
|
}
|
|
|
|
/* Week container for sliding */
|
|
swp-grid-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;
|
|
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 15px;
|
|
font-size: 0.75rem;
|
|
color: var(--color-text-secondary);
|
|
display: flex;
|
|
align-items: flex-start;
|
|
position: relative;
|
|
|
|
&::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: -1px;
|
|
left: 50px;
|
|
width: calc(100vw - 60px);
|
|
height: 1px;
|
|
background: var(--color-hour-line);
|
|
z-index: 2;
|
|
}
|
|
}
|
|
|
|
/* Week header - dynamic height based on content */
|
|
swp-calendar-header {
|
|
display: grid;
|
|
grid-template-columns: repeat(var(--grid-columns, 7), minmax(var(--day-column-min-width), 1fr));
|
|
grid-template-rows: var(--header-height) auto;
|
|
min-width: calc(var(--grid-columns, 7) * var(--day-column-min-width));
|
|
background: var(--color-surface);
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 3;
|
|
height: calc(var(--header-height) + var(--all-day-row-height));
|
|
overflow-y: scroll;
|
|
overflow-x: hidden;
|
|
|
|
/* WebKit browsers - hide scrollbar but keep space */
|
|
&::-webkit-scrollbar {
|
|
width: 17px;
|
|
background: transparent;
|
|
}
|
|
|
|
&::-webkit-scrollbar-thumb {
|
|
background: transparent;
|
|
}
|
|
|
|
&::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
|
|
/* All-day events container */
|
|
swp-allday-container {
|
|
grid-column: 1 / -1;
|
|
grid-row: 2;
|
|
display: grid;
|
|
grid-template-columns: repeat(var(--grid-columns, 7), minmax(var(--day-column-min-width), 1fr));
|
|
grid-auto-rows: var(--single-row-height);
|
|
gap: 2px 0px;
|
|
align-items: center;
|
|
overflow: hidden;
|
|
|
|
/* Border only when events exist */
|
|
&:has(swp-allday-event) {
|
|
border-bottom: 1px solid var(--color-grid-line);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Day headers */
|
|
swp-day-header {
|
|
grid-row: 1;
|
|
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;
|
|
padding-top: 3px;
|
|
|
|
&:last-child {
|
|
border-right: none;
|
|
}
|
|
|
|
&[data-today="true"] {
|
|
background: rgba(33, 150, 243, 0.1);
|
|
|
|
swp-day-name {
|
|
color: var(--color-primary);
|
|
font-weight: 600;
|
|
}
|
|
|
|
swp-day-date {
|
|
color: var(--color-primary);
|
|
}
|
|
}
|
|
}
|
|
|
|
swp-day-name {
|
|
display: block;
|
|
font-weight: 500;
|
|
font-size: 12px;
|
|
color: var(--color-text-secondary);
|
|
letter-spacing: 0.1em;
|
|
}
|
|
|
|
swp-day-date {
|
|
display: block;
|
|
font-size: 30px;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
/* Resource header styling */
|
|
swp-resource-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;
|
|
background: var(--color-surface);
|
|
|
|
&:last-child {
|
|
border-right: none;
|
|
}
|
|
}
|
|
|
|
swp-resource-avatar {
|
|
display: block;
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
overflow: hidden;
|
|
margin-bottom: 8px;
|
|
background: var(--color-border);
|
|
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
}
|
|
|
|
swp-resource-name {
|
|
display: block;
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
color: var(--color-text);
|
|
text-align: center;
|
|
}
|
|
|
|
/* Ghost columns for mouseenter events */
|
|
swp-allday-column {
|
|
position: relative;
|
|
opacity: 0;
|
|
background: transparent;
|
|
z-index: 1;
|
|
height: 100%;
|
|
}
|
|
|
|
/* All-day events - MASSIVELY OPTIMIZED with nesting */
|
|
swp-allday-container {
|
|
swp-allday-event {
|
|
height: 22px !important;
|
|
position: relative !important;
|
|
width: auto !important;
|
|
left: auto !important;
|
|
right: auto !important;
|
|
top: auto !important;
|
|
margin: 1px;
|
|
padding: 2px 4px;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
background: hsl(208, 100%, 50%);
|
|
display: flex;
|
|
z-index: 2;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
color: #fff;
|
|
font-size: 0.75rem;
|
|
border-radius: 3px;
|
|
|
|
/* Event type colors - normal state */
|
|
&[data-type="meeting"] {
|
|
background: var(--color-event-meeting);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
&[data-type="meal"] {
|
|
background: var(--color-event-meal);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
&[data-type="work"] {
|
|
background: var(--color-event-work);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
&[data-type="milestone"] {
|
|
background: var(--color-event-milestone);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
&[data-type="personal"] {
|
|
background: var(--color-event-personal);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
&[data-type="deadline"] {
|
|
background: var(--color-event-milestone);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
/* Dragging state */
|
|
&.dragging {
|
|
opacity: 1;
|
|
}
|
|
|
|
/* Highlight state for all event types */
|
|
&.highlight {
|
|
&[data-type="meeting"] {
|
|
background: var(--color-event-meeting-hl) !important;
|
|
}
|
|
|
|
&[data-type="meal"] {
|
|
background: var(--color-event-meal-hl) !important;
|
|
}
|
|
|
|
&[data-type="work"] {
|
|
background: var(--color-event-work-hl) !important;
|
|
}
|
|
|
|
&[data-type="milestone"] {
|
|
background: var(--color-event-milestone-hl) !important;
|
|
}
|
|
|
|
&[data-type="personal"] {
|
|
background: var(--color-event-personal-hl) !important;
|
|
}
|
|
|
|
&[data-type="deadline"] {
|
|
background: var(--color-event-milestone-hl) !important;
|
|
}
|
|
}
|
|
|
|
/* Overflow indicator styling */
|
|
&.max-event-indicator {
|
|
background: #e0e0e0 !important;
|
|
color: #666 !important;
|
|
border: 1px dashed #999 !important;
|
|
cursor: pointer !important;
|
|
text-align: center !important;
|
|
font-style: italic;
|
|
opacity: 0.8;
|
|
justify-content: center;
|
|
|
|
&:hover {
|
|
background: #d0d0d0 !important;
|
|
color: #333 !important;
|
|
opacity: 1;
|
|
}
|
|
|
|
span {
|
|
display: block;
|
|
width: 100%;
|
|
text-align: center;
|
|
font-size: 11px;
|
|
font-weight: normal;
|
|
}
|
|
}
|
|
|
|
&.max-event-overflow-show {
|
|
opacity: 1;
|
|
transition: opacity 0.3s ease-in-out;
|
|
}
|
|
|
|
&.max-event-overflow-hide {
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease-in-out;
|
|
}
|
|
|
|
/* Child elements - no classes needed! */
|
|
swp-event-time {
|
|
display: none;
|
|
}
|
|
|
|
swp-event-title {
|
|
display: block;
|
|
font-size: 12px;
|
|
line-height: 18px;
|
|
}
|
|
|
|
&.transitioning {
|
|
transition: grid-area 200ms ease-out, grid-row 200ms ease-out, grid-column 200ms ease-out;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Scrollable content */
|
|
swp-scrollable-content {
|
|
overflow-y: auto;
|
|
overflow-x: auto;
|
|
scroll-behavior: smooth;
|
|
position: relative;
|
|
display: grid;
|
|
top: -1px;
|
|
|
|
/* Style native scrollbars for Webkit browsers */
|
|
&::-webkit-scrollbar {
|
|
width: var(--scrollbar-width, 12px);
|
|
height: var(--scrollbar-width, 12px);
|
|
}
|
|
|
|
&::-webkit-scrollbar-track {
|
|
background: var(--scrollbar-track-color, #f0f0f0);
|
|
}
|
|
|
|
&::-webkit-scrollbar-thumb {
|
|
background: var(--scrollbar-color, #666);
|
|
border-radius: var(--scrollbar-border-radius, 6px);
|
|
|
|
&:hover {
|
|
background: var(--scrollbar-hover-color, #333);
|
|
}
|
|
}
|
|
|
|
/* Style native scrollbars for Firefox */
|
|
scrollbar-width: auto;
|
|
scrollbar-color: var(--scrollbar-color, #666) var(--scrollbar-track-color, #f0f0f0);
|
|
}
|
|
|
|
/* Time grid */
|
|
swp-time-grid {
|
|
position: relative;
|
|
height: calc((var(--day-end-hour) - var(--day-start-hour)) * var(--hour-height));
|
|
|
|
/* Global work hours overlay - disabled */
|
|
&::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
height: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background: transparent;
|
|
min-width: calc(var(--grid-columns, 7) * var(--day-column-min-width));
|
|
display: none;
|
|
}
|
|
|
|
/* Add hour lines as background */
|
|
&::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
min-width: calc(var(--grid-columns, 7) * var(--day-column-min-width));
|
|
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));
|
|
z-index: 1;
|
|
}
|
|
}
|
|
|
|
/* Grid lines */
|
|
swp-grid-lines {
|
|
position: absolute;
|
|
top: 0px;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
min-width: calc(var(--grid-columns, 7) * var(--day-column-min-width));
|
|
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(var(--grid-columns, 7), minmax(var(--day-column-min-width), 1fr));
|
|
min-width: calc(var(--grid-columns, 7) * var(--day-column-min-width));
|
|
|
|
swp-event {
|
|
/* Placeholder for event styles from calendar-events-css.css */
|
|
}
|
|
}
|
|
|
|
/* Day column with work hours */
|
|
swp-day-column {
|
|
position: relative;
|
|
border-right: 1px solid var(--color-grid-line);
|
|
min-width: var(--day-column-min-width);
|
|
background: var(--color-event-grid);
|
|
|
|
&:last-child {
|
|
border-right: none;
|
|
}
|
|
|
|
/* Per-column non-work hours overlays */
|
|
&::before,
|
|
&::after {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
background: var(--color-non-work-hours);
|
|
z-index: 2;
|
|
opacity: 0.3;
|
|
}
|
|
|
|
&::before {
|
|
top: 0;
|
|
height: var(--before-work-height, 0px);
|
|
}
|
|
|
|
&::after {
|
|
top: var(--after-work-top, 100%);
|
|
bottom: 0;
|
|
}
|
|
|
|
/* Full day overlay when day is off */
|
|
&[data-work-hours="off"] {
|
|
background: var(--color-non-work-hours);
|
|
|
|
&::before,
|
|
&::after {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Resource column styling */
|
|
swp-resource-column {
|
|
position: relative;
|
|
border-right: 1px solid var(--color-grid-line);
|
|
min-width: var(--day-column-min-width);
|
|
background: var(--color-event-grid);
|
|
|
|
&:last-child {
|
|
border-right: none;
|
|
}
|
|
}
|
|
|
|
swp-events-layer {
|
|
position: absolute;
|
|
inset: 0;
|
|
display: block;
|
|
z-index: var(--z-event);
|
|
}
|
|
|
|
/* Current time indicator */
|
|
swp-current-time-indicator {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
height: 2px;
|
|
background: var(--color-current-time);
|
|
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);
|
|
}
|
|
} |