diff --git a/calendar.css b/calendar.css index 354c4e8..9597771 100644 --- a/calendar.css +++ b/calendar.css @@ -1,328 +1,6 @@ -/* Color tokens */ -:root { - --bg: #f6f7fb; - --panel: #fff; - --today: #f83; - --ink: #111; - --ink-rgb: 17, 17, 17; - --muted: #888; - --weekend: #888; - --firstday: #000; - --select: #aaf; - --label-bg: #fafbfe; - --label-bg-rgb: 250, 251, 254; - - /* Layout */ - --row-h: 2.2em; - --label-w: minmax(4em, 8%); - --cell-w: 1fr; - --cell-h: clamp(4em, 8vh, 8em); - --overlay-w: minmax(3rem, 5%); -} - -/* Prevent text selection in calendar */ -#calendar-viewport, #calendar-content, .week-row, .cell, -.calendar-header, .week-label, .month-name-label, -.calendar-container, .jogwheel-viewport, .jogwheel-content { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-touch-callout: none; - -webkit-tap-highlight-color: transparent; -} - -/* Month tints (light) */ -.dec { background: hsl(220 20% 95%) } -.jan { background: hsl(220 20% 88%) } -.feb { background: hsl(220 20% 95%) } -.mar { background: hsl(125 60% 88%) } -.apr { background: hsl(125 60% 95%) } -.may { background: hsl(125 60% 88%) } -.jun { background: hsl(45 85% 95%) } -.jul { background: hsl(45 85% 88%) } -.aug { background: hsl(45 85% 95%) } -.sep { background: hsl(18 78% 88%) } -.oct { background: hsl(18 78% 95%) } -.nov { background: hsl(18 78% 88%) } - -/* Color tokens (dark) */ -@media (prefers-color-scheme: dark) { - :root { - --bg: radial-gradient(1200px 800px at 20% -10%, #1c2130 0%, #0c0f16 35%, #0a0b11 100%); - --panel: #111318; - --today: #f83; - --ink: #ddd; - --ink-rgb: 221, 221, 221; - --muted: #888; - --weekend: #999; - --firstday: #fff; - --select: #44f; - --label-bg: #1a1d25; - --label-bg-rgb: 26, 29, 37; - } - - /* Month tints (dark) */ - .dec { background: hsl(220 20% 22%) } - .jan { background: hsl(220 20% 16%) } - .feb { background: hsl(220 20% 22%) } - .mar { background: hsl(125 40% 18%) } - .apr { background: hsl(125 40% 26%) } - .may { background: hsl(125 40% 18%) } - .jun { background: hsl(45 70% 24%) } - .jul { background: hsl(45 70% 18%) } - .aug { background: hsl(45 70% 24%) } - .sep { background: hsl(18 70% 18%) } - .oct { background: hsl(18 70% 26%) } - .nov { background: hsl(18 70% 18%) } -} - -/* Layout & typography */ -* { box-sizing: border-box } - -body { - margin: 0; - font: 500 14px/1.2 ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Inter, Arial; - background: var(--bg); - color: var(--ink); -} - -.wrap { - width: 100%; - margin: 0; - background: var(--panel); - height: 100vh; - display: flex; - flex-direction: column; - padding: 1rem; - white-space: pre-wrap; -} - -header { - display: flex; - align-items: baseline; - justify-content: space-between; - margin-bottom: .75rem; - flex-shrink: 0; -} - -.header-controls { - display: flex; - align-items: center; - gap: .75rem; -} - -.today-date { cursor: pointer } -.today-date::first-line { color: var(--today) } -.today-button:hover { opacity: .8 } - -/* Header row */ -.calendar-header, #calendar-header { - display: grid; - grid-template-columns: var(--label-w) repeat(7, var(--cell-w)) var(--overlay-w); - border-bottom: .1em solid var(--muted); - align-items: last baseline; - flex-shrink: 0; - width: 100%; -} -.calendar-header .dow-label { display:grid; place-items:center; height: var(--cell-h); color: var(--muted) } -.overlay-header-spacer { grid-column: -2 / -1 } - -/* Main container */ -.calendar-container, #calendar-container { - flex: 1; - overflow: hidden; - position: relative; - width: 100%; - display: flex; -} - -/* Viewports (support id or class) */ -.calendar-viewport, #calendar-viewport { - height: 100%; - overflow-y: auto; - overflow-x: hidden; - flex: 1; - width: 100%; - scrollbar-width: none; -} -.calendar-viewport::-webkit-scrollbar, -#calendar-viewport::-webkit-scrollbar { display: none } - -.jogwheel-viewport, #jogwheel-viewport { - position: absolute; - top: 0; right: 0; bottom: 0; - width: var(--overlay-w); - overflow-y: auto; - overflow-x: hidden; - scrollbar-width: none; - z-index: 20; - cursor: ns-resize; -} -.jogwheel-viewport::-webkit-scrollbar, -#jogwheel-viewport::-webkit-scrollbar { display: none } - -.jogwheel-content, #jogwheel-content { position: relative; width: 100% } -.calendar-content, #calendar-content { position: relative } - -/* Week row: label + 7-day grid + jogwheel column */ -.week-row { - display: grid; - grid-template-columns: var(--label-w) repeat(7, var(--cell-w)) var(--overlay-w); - position: relative; - overflow: visible; - height: var(--cell-h); - scroll-snap-align: start; - width: 100%; -} - -/* Label cells */ -.dow-label, .week-label { - display: grid; - place-items: center; - width: 100%; - height: var(--cell-h); - color: var(--muted); - cursor: ns-resize; - font-size: 1.2em; -} - -/* 7-day grid inside each week row */ -.week-row > .days-grid { - grid-column: 2 / span 7; - display: grid; - grid-template-columns: repeat(7, 1fr); - grid-auto-rows: 1fr; - position: relative; - height: 100%; - width: 100%; -} - -/* Overlay sitting above the day cells, same 7-col grid */ -.week-row > .days-grid > .week-overlay { - margin-top: 1.2em; - position: absolute; - inset: 0; - pointer-events: none; - display: grid; - grid-template-columns: repeat(7, 1fr); - grid-auto-rows: 1fr; - z-index: 15; -} - -/* Day cells */ -.dow { text-transform: uppercase } -.cell { - position: relative; - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: flex-start; - padding: .25em; - overflow: hidden; - width: 100%; - height: var(--cell-h); - font-weight: 700; - cursor: pointer; - transition: background-color .15s ease; -} -.cell h1 { - top: .25em; - right: .25em; - padding: 0; - margin: 0; - transition: background-color .15s ease; - font-size: 1em; -} -.cell:hover h1 { text-shadow: 0 0 .2em } - -/* Fixed heights for cells and labels */ -.week-row .cell, .week-row .week-label { height: var(--cell-h) } - -/* Event (per-cell, if used) */ -.event { - font-size: .75em; - padding: .1em .3em; - margin: .1em 0; - border-radius: .2em; - color: white; - font-weight: 500; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 100%; - max-width: calc(100% - .5em); - line-height: 1.2; - cursor: pointer; - z-index: 5; -} -.event:hover { opacity: .8 } - -/* Spanning events in the overlay (grid-positioned, not absolutely measured) */ -.event-span { - font-size: .75em; - padding: 0 .5em; - border-radius: .4em; - color: white; - font-weight: 600; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - line-height: 1.2; - height: 1.2em; - align-self: center; /* vertically center within the overlay row */ - justify-self: stretch; /* stretch across chosen grid columns */ - pointer-events: auto; /* clickable despite overlay having none */ - z-index: 1; -} - -/* Selection styles */ -.weekend { color: var(--weekend) } -.firstday { color: var(--firstday); text-shadow: 0 0 .1em rgba(var(--ink-rgb), .5) } - -input { - background: transparent; - border: none; - color: var(--ink); - width: 11em; -} -label:has(input[value]) { display: block } - -.selected { - background: var(--select); - border: 2px solid rgba(var(--ink-rgb), .3); - box-shadow: inset 0 0 0 1px rgba(255,255,255,.3); -} -.selected .event { opacity: .7 } - -.today h1 { - border-radius: 2em; - background: var(--today); - border: .2em solid var(--today); - margin: -.2em; -} - - -.month-name-label { - grid-column: -2 / -1; - font-size: 2em; - font-weight: 700; - color: var(--muted); - display: flex; - align-items: center; - justify-content: center; - pointer-events: none; - z-index: 15; - overflow: visible; - position: absolute; - top: 0; right: 0; - width: 100%; -} -.month-name-label > span { - display: inline-block; - white-space: nowrap; - writing-mode: vertical-rl; - text-orientation: mixed; - transform: rotate(180deg); - transform-origin: center; -} +/* Calendar CSS - Main file with imports */ +@import url('colors.css'); +@import url('layout.css'); +@import url('cells.css'); +@import url('events.css'); +@import url('utilities.css'); diff --git a/cells.css b/cells.css new file mode 100644 index 0000000..c0960d9 --- /dev/null +++ b/cells.css @@ -0,0 +1,28 @@ +/* Day cells */ +.dow { text-transform: uppercase } +.cell { + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + padding: .25em; + overflow: hidden; + width: 100%; + height: var(--cell-h); + font-weight: 700; + cursor: pointer; + transition: background-color .15s ease; +} +.cell h1 { + top: .25em; + right: .25em; + padding: 0; + margin: 0; + transition: background-color .15s ease; + font-size: 1em; +} +.cell:hover h1 { text-shadow: 0 0 .2em } + +/* Fixed heights for cells and labels */ +.week-row .cell, .week-row .week-label { height: var(--cell-h) } diff --git a/colors.css b/colors.css new file mode 100644 index 0000000..dcbb2c2 --- /dev/null +++ b/colors.css @@ -0,0 +1,77 @@ +/* Color tokens */ +:root { + --bg: #f6f7fb; + --panel: #fff; + --today: #f83; + --ink: #111; + --ink-rgb: 17, 17, 17; + --muted: #888; + --weekend: #888; + --firstday: #000; + --select: #aaf; + --label-bg: #fafbfe; + --label-bg-rgb: 250, 251, 254; +} + +/* Month tints (light) */ +.dec { background: hsl(220 20% 95%) } +.jan { background: hsl(220 20% 88%) } +.feb { background: hsl(220 20% 95%) } +.mar { background: hsl(125 60% 88%) } +.apr { background: hsl(125 60% 95%) } +.may { background: hsl(125 60% 88%) } +.jun { background: hsl(45 85% 95%) } +.jul { background: hsl(45 85% 88%) } +.aug { background: hsl(45 85% 95%) } +.sep { background: hsl(18 78% 88%) } +.oct { background: hsl(18 78% 95%) } +.nov { background: hsl(18 78% 88%) } + +/* Color tokens (dark) */ +@media (prefers-color-scheme: dark) { + :root { + --bg: radial-gradient(1200px 800px at 20% -10%, #1c2130 0%, #0c0f16 35%, #0a0b11 100%); + --panel: #111318; + --today: #f83; + --ink: #ddd; + --ink-rgb: 221, 221, 221; + --muted: #888; + --weekend: #999; + --firstday: #fff; + --select: #44f; + --label-bg: #1a1d25; + --label-bg-rgb: 26, 29, 37; + } + + /* Month tints (dark) */ + .dec { background: hsl(220 20% 22%) } + .jan { background: hsl(220 20% 16%) } + .feb { background: hsl(220 20% 22%) } + .mar { background: hsl(125 40% 18%) } + .apr { background: hsl(125 40% 26%) } + .may { background: hsl(125 40% 18%) } + .jun { background: hsl(45 70% 24%) } + .jul { background: hsl(45 70% 18%) } + .aug { background: hsl(45 70% 24%) } + .sep { background: hsl(18 70% 18%) } + .oct { background: hsl(18 70% 26%) } + .nov { background: hsl(18 70% 18%) } +} + +/* Selection styles */ +.weekend { color: var(--weekend) } +.firstday { color: var(--firstday); text-shadow: 0 0 .1em rgba(var(--ink-rgb), .5) } + +.selected { + background: var(--select); + border: 2px solid rgba(var(--ink-rgb), .3); + box-shadow: inset 0 0 0 1px rgba(255,255,255,.3); +} +.selected .event { opacity: .7 } + +.today h1 { + border-radius: 2em; + background: var(--today); + border: .2em solid var(--today); + margin: -.2em; +} diff --git a/events.css b/events.css new file mode 100644 index 0000000..19cee94 --- /dev/null +++ b/events.css @@ -0,0 +1,36 @@ +/* Event (per-cell, if used) */ +.event { + font-size: .75em; + padding: .1em .3em; + margin: .1em 0; + border-radius: .2em; + color: white; + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + width: 100%; + max-width: calc(100% - .5em); + line-height: 1.2; + cursor: pointer; + z-index: 5; +} +.event:hover { opacity: .8 } + +/* Spanning events in the overlay (grid-positioned, not absolutely measured) */ +.event-span { + font-size: .75em; + padding: 0 .5em; + border-radius: .4em; + color: white; + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: 1.2; + height: 1.2em; + align-self: center; /* vertically center within the overlay row */ + justify-self: stretch; /* stretch across chosen grid columns */ + pointer-events: auto; /* clickable despite overlay having none */ + z-index: 1; +} diff --git a/layout.css b/layout.css new file mode 100644 index 0000000..d3a1d01 --- /dev/null +++ b/layout.css @@ -0,0 +1,166 @@ +/* Layout variables */ +:root { + /* Layout */ + --row-h: 2.2em; + --label-w: minmax(4em, 8%); + --cell-w: 1fr; + --cell-h: clamp(4em, 8vh, 8em); + --overlay-w: minmax(3rem, 5%); +} + +/* Layout & typography */ +* { box-sizing: border-box } + +body { + margin: 0; + font: 500 14px/1.2 ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Inter, Arial; + background: var(--bg); + color: var(--ink); +} + +.wrap { + width: 100%; + margin: 0; + background: var(--panel); + height: 100vh; + display: flex; + flex-direction: column; + padding: 1rem; + white-space: pre-wrap; +} + +header { + display: flex; + align-items: baseline; + justify-content: space-between; + margin-bottom: .75rem; + flex-shrink: 0; +} + +.header-controls { + display: flex; + align-items: center; + gap: .75rem; +} + +.today-date { cursor: pointer } +.today-date::first-line { color: var(--today) } +.today-button:hover { opacity: .8 } + +/* Header row */ +.calendar-header, #calendar-header { + display: grid; + grid-template-columns: var(--label-w) repeat(7, var(--cell-w)) var(--overlay-w); + border-bottom: .1em solid var(--muted); + align-items: last baseline; + flex-shrink: 0; + width: 100%; +} +.calendar-header .dow-label { display:grid; place-items:center; height: var(--cell-h); color: var(--muted) } +.overlay-header-spacer { grid-column: -2 / -1 } + +/* Main container */ +.calendar-container, #calendar-container { + flex: 1; + overflow: hidden; + position: relative; + width: 100%; + display: flex; +} + +/* Viewports (support id or class) */ +.calendar-viewport, #calendar-viewport { + height: 100%; + overflow-y: auto; + overflow-x: hidden; + flex: 1; + width: 100%; + scrollbar-width: none; +} +.calendar-viewport::-webkit-scrollbar, +#calendar-viewport::-webkit-scrollbar { display: none } + +.jogwheel-viewport, #jogwheel-viewport { + position: absolute; + top: 0; right: 0; bottom: 0; + width: var(--overlay-w); + overflow-y: auto; + overflow-x: hidden; + scrollbar-width: none; + z-index: 20; + cursor: ns-resize; +} +.jogwheel-viewport::-webkit-scrollbar, +#jogwheel-viewport::-webkit-scrollbar { display: none } + +.jogwheel-content, #jogwheel-content { position: relative; width: 100% } +.calendar-content, #calendar-content { position: relative } + +/* Week row: label + 7-day grid + jogwheel column */ +.week-row { + display: grid; + grid-template-columns: var(--label-w) repeat(7, var(--cell-w)) var(--overlay-w); + position: relative; + overflow: visible; + height: var(--cell-h); + scroll-snap-align: start; + width: 100%; +} + +/* Label cells */ +.dow-label, .week-label { + display: grid; + place-items: center; + width: 100%; + height: var(--cell-h); + color: var(--muted); + cursor: ns-resize; + font-size: 1.2em; +} + +/* 7-day grid inside each week row */ +.week-row > .days-grid { + grid-column: 2 / span 7; + display: grid; + grid-template-columns: repeat(7, 1fr); + grid-auto-rows: 1fr; + position: relative; + height: 100%; + width: 100%; +} + +/* Overlay sitting above the day cells, same 7-col grid */ +.week-row > .days-grid > .week-overlay { + margin-top: 1.2em; + position: absolute; + inset: 0; + pointer-events: none; + display: grid; + grid-template-columns: repeat(7, 1fr); + grid-auto-rows: 1fr; + z-index: 15; +} + +.month-name-label { + grid-column: -2 / -1; + font-size: 2em; + font-weight: 700; + color: var(--muted); + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; + z-index: 15; + overflow: visible; + position: absolute; + top: 0; right: 0; + width: 100%; +} +.month-name-label > span { + display: inline-block; + white-space: nowrap; + writing-mode: vertical-rl; + text-orientation: mixed; + transform: rotate(180deg); + transform-origin: center; +} diff --git a/utilities.css b/utilities.css new file mode 100644 index 0000000..fd88bdf --- /dev/null +++ b/utilities.css @@ -0,0 +1,19 @@ +/* Prevent text selection in calendar */ +#calendar-viewport, #calendar-content, .week-row, .cell, +.calendar-header, .week-label, .month-name-label, +.calendar-container, .jogwheel-viewport, .jogwheel-content { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-touch-callout: none; + -webkit-tap-highlight-color: transparent; +} + +input { + background: transparent; + border: none; + color: var(--ink); + width: 11em; +} +label:has(input[value]) { display: block }