Introduces ScrollManager to synchronize time axis and header scrolling Improves user experience by keeping time axis and header aligned during scrolling Enables dynamic vertical and horizontal scroll tracking for calendar components
263 lines
5.1 KiB
CSS
263 lines
5.1 KiB
CSS
:root {
|
|
--hour-height: 60px;
|
|
--time-axis-width: 60px;
|
|
--grid-columns: 5;
|
|
--day-start-hour: 0;
|
|
--day-end-hour: 24;
|
|
--color-border: #e0e0e0;
|
|
--color-surface: #fff;
|
|
--color-text-secondary: #666;
|
|
--color-primary: #1976d2;
|
|
}
|
|
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
background: #f5f5f5;
|
|
}
|
|
|
|
.calendar-wrapper {
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
swp-calendar {
|
|
display: grid;
|
|
grid-template-rows: auto 1fr;
|
|
height: 100%;
|
|
background: var(--color-surface);
|
|
}
|
|
|
|
/* Nav */
|
|
swp-calendar-nav {
|
|
display: flex;
|
|
gap: 16px;
|
|
padding: 12px 16px;
|
|
border-bottom: 1px solid var(--color-border);
|
|
align-items: center;
|
|
}
|
|
|
|
swp-nav-button {
|
|
padding: 8px 16px;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
background: var(--color-surface);
|
|
}
|
|
|
|
swp-nav-button:hover { background: #f0f0f0; }
|
|
|
|
swp-week-info {
|
|
margin-left: auto;
|
|
text-align: right;
|
|
}
|
|
|
|
swp-week-number {
|
|
font-weight: 600;
|
|
display: block;
|
|
}
|
|
|
|
swp-date-range {
|
|
font-size: 12px;
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
/* Container */
|
|
swp-calendar-container {
|
|
display: grid;
|
|
grid-template-columns: var(--time-axis-width) 1fr;
|
|
grid-template-rows: auto 1fr;
|
|
overflow: hidden;
|
|
height: 100%;
|
|
}
|
|
|
|
/* Time axis */
|
|
swp-time-axis {
|
|
grid-column: 1;
|
|
grid-row: 1 / 3;
|
|
display: grid;
|
|
grid-template-rows: subgrid;
|
|
border-right: 1px solid var(--color-border);
|
|
background: var(--color-surface);
|
|
overflow: hidden;
|
|
}
|
|
|
|
swp-header-spacer {
|
|
border-bottom: 1px solid var(--color-border);
|
|
}
|
|
|
|
swp-time-axis-content {
|
|
display: grid;
|
|
grid-auto-rows: var(--hour-height);
|
|
overflow: hidden;
|
|
}
|
|
|
|
swp-hour-marker {
|
|
height: var(--hour-height);
|
|
padding: 4px 8px;
|
|
font-size: 11px;
|
|
color: var(--color-text-secondary);
|
|
text-align: right;
|
|
}
|
|
|
|
/* Grid container */
|
|
swp-grid-container {
|
|
grid-column: 2;
|
|
grid-row: 1 / 3;
|
|
display: grid;
|
|
grid-template-rows: subgrid;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* Viewport/Track for slide animation */
|
|
swp-header-viewport {
|
|
overflow: hidden;
|
|
}
|
|
|
|
swp-content-viewport {
|
|
overflow: hidden;
|
|
min-height: 0; /* Tillader at krympe i grid */
|
|
}
|
|
|
|
swp-header-track {
|
|
display: flex;
|
|
}
|
|
|
|
swp-content-track {
|
|
display: flex;
|
|
height: 100%;
|
|
}
|
|
|
|
swp-header-track > swp-calendar-header {
|
|
flex: 0 0 100%;
|
|
}
|
|
|
|
swp-content-track > swp-scrollable-content {
|
|
flex: 0 0 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
/* Header */
|
|
swp-calendar-header {
|
|
display: grid;
|
|
grid-template-columns: repeat(var(--grid-columns), 1fr);
|
|
grid-auto-rows: auto;
|
|
background: var(--color-surface);
|
|
overflow-y: scroll;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
swp-calendar-header::-webkit-scrollbar {
|
|
background: transparent;
|
|
}
|
|
|
|
swp-calendar-header::-webkit-scrollbar-thumb {
|
|
background: transparent;
|
|
}
|
|
|
|
swp-calendar-header[data-levels="date"] > swp-day-header { grid-row: 1; }
|
|
|
|
swp-calendar-header[data-levels="resource date"] > swp-resource-header { grid-row: 1; }
|
|
swp-calendar-header[data-levels="resource date"] > swp-day-header { grid-row: 2; }
|
|
|
|
swp-calendar-header[data-levels="team resource date"] > swp-team-header { grid-row: 1; }
|
|
swp-calendar-header[data-levels="team resource date"] > swp-resource-header { grid-row: 2; }
|
|
swp-calendar-header[data-levels="team resource date"] > swp-day-header { grid-row: 3; }
|
|
|
|
swp-day-header,
|
|
swp-resource-header,
|
|
swp-team-header {
|
|
padding: 8px;
|
|
text-align: center;
|
|
border-right: 1px solid var(--color-border);
|
|
border-bottom: 1px solid var(--color-border);
|
|
}
|
|
|
|
swp-team-header {
|
|
background: #e3f2fd;
|
|
color: #1565c0;
|
|
font-weight: 500;
|
|
}
|
|
|
|
swp-resource-header {
|
|
background: #fafafa;
|
|
font-size: 13px;
|
|
}
|
|
|
|
swp-day-name {
|
|
display: block;
|
|
font-size: 11px;
|
|
color: var(--color-text-secondary);
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
swp-day-date {
|
|
display: block;
|
|
font-size: 24px;
|
|
font-weight: 300;
|
|
}
|
|
|
|
/* Scrollable content */
|
|
swp-scrollable-content {
|
|
display: block;
|
|
overflow: auto;
|
|
}
|
|
|
|
swp-time-grid {
|
|
display: block;
|
|
position: relative;
|
|
min-height: calc((var(--day-end-hour) - var(--day-start-hour)) * var(--hour-height));
|
|
}
|
|
|
|
swp-grid-lines {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: repeating-linear-gradient(
|
|
to bottom,
|
|
transparent,
|
|
transparent calc(var(--hour-height) - 1px),
|
|
var(--color-border) calc(var(--hour-height) - 1px),
|
|
var(--color-border) var(--hour-height)
|
|
);
|
|
}
|
|
|
|
swp-day-columns {
|
|
position: absolute;
|
|
inset: 0;
|
|
display: grid;
|
|
grid-template-columns: repeat(var(--grid-columns), 1fr);
|
|
}
|
|
|
|
swp-day-column {
|
|
position: relative;
|
|
border-right: 1px solid var(--color-border);
|
|
}
|
|
|
|
swp-events-layer {
|
|
position: absolute;
|
|
inset: 0;
|
|
}
|
|
|
|
/* Events */
|
|
swp-event {
|
|
position: absolute;
|
|
background: var(--color-primary);
|
|
color: white;
|
|
border-radius: 4px;
|
|
padding: 4px 6px;
|
|
font-size: 12px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
swp-event-time {
|
|
display: block;
|
|
font-size: 10px;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
swp-event-title {
|
|
display: block;
|
|
font-weight: 500;
|
|
}
|