2020 --accent-4 : # 00aaff ;
2121 }
2222
23+ @media (prefers-color-scheme : dark) {
24+ : root {
25+ --bg : # 2a2a2a ;
26+ --surface : # 383838 ;
27+ --surface-2 : # 4a4a4a ;
28+ --border : # 555555 ;
29+ --text : # d4d4d4 ;
30+ --text-dim : # 9a9a9a ;
31+ }
32+ }
33+
2334 * {
2435 margin : 0 ;
2536 padding : 0 ;
414425 margin-top : 0.1rem ;
415426 }
416427
417- @media (max-width : 900px ) {
418- .month-grid {
419- grid-template-columns : repeat (2 , minmax (0 , 1fr ));
420- }
428+ .scroll-top-btn {
429+ position : fixed;
430+ right : 1.25rem ;
431+ bottom : 1.25rem ;
432+ width : 48px ;
433+ height : 48px ;
434+ border-radius : 50% ;
435+ background : var (--text );
436+ color : var (--bg );
437+ border : 1px solid var (--border );
438+ font-size : 1.4rem ;
439+ line-height : 1 ;
440+ cursor : pointer;
441+ display : none;
442+ align-items : center;
443+ justify-content : center;
444+ z-index : 100 ;
445+ box-shadow : 0 2px 8px rgba (0 , 0 , 0 , 0.2 );
446+ transition : transform 0.2s , opacity 0.2s ;
447+ }
421448
422- .month-grid-header {
423- display : none;
424- }
449+ .scroll-top-btn .visible {
450+ display : flex;
451+ }
452+
453+ .scroll-top-btn : hover {
454+ transform : translateY (-2px );
425455 }
426456
427457 @media (max-width : 768px ) {
428458 .container {
429- padding : 1 rem ;
459+ padding : 0.75 rem ;
430460 }
431461
432462 h1 {
435465
436466 .controls {
437467 flex-direction : column;
468+ padding : 1rem ;
438469 }
439470
440471 .view-controls {
445476 flex : 1 ;
446477 }
447478
479+ .month-grid-header {
480+ gap : 2px ;
481+ }
482+
483+ .month-weekday {
484+ font-size : 0.6rem ;
485+ padding : 0.15rem 0 ;
486+ letter-spacing : 0 ;
487+ }
488+
448489 .month-grid {
449- grid-template-columns : 1fr ;
490+ grid-template-columns : repeat (7 , minmax (0 , 1fr ));
491+ gap : 2px ;
492+ }
493+
494+ .month-cell {
495+ min-height : 56px ;
496+ padding : 0.2rem ;
497+ }
498+
499+ .month-cell-day {
500+ font-size : 0.7rem ;
501+ margin-bottom : 0.2rem ;
502+ }
503+
504+ .month-cell-events {
505+ gap : 0.15rem ;
506+ }
507+
508+ .month-event {
509+ font-size : 0.6rem ;
510+ gap : 0.15rem ;
511+ }
512+
513+ .month-event-text {
514+ display : none;
515+ }
516+
517+ .month-event-dot {
518+ width : 6px ;
519+ height : 6px ;
520+ margin-top : 0 ;
521+ }
522+
523+ .month-more {
524+ font-size : 0.55rem ;
525+ }
526+
527+ .scroll-top-btn {
528+ right : 0.75rem ;
529+ bottom : 0.75rem ;
530+ width : 42px ;
531+ height : 42px ;
450532 }
451533 }
452534 </ style >
@@ -472,6 +554,8 @@ <h1>Codam Calendar</h1>
472554 </ div >
473555 </ div >
474556
557+ < button id ="scrollTopBtn " class ="scroll-top-btn " aria-label ="Scroll to top " title ="Scroll to top "> ↑</ button >
558+
475559 < script >
476560 const CALENDARS = [
477561 {
@@ -504,7 +588,8 @@ <h1>Codam Calendar</h1>
504588 events : [ ] ,
505589 monthCursor : new Date ( ) ,
506590 agendaStart : new Date ( ) ,
507- agendaFocusDate : null
591+ agendaFocusDate : null ,
592+ agendaFocusScrolled : false
508593 } ;
509594
510595 function initToggles ( ) {
@@ -530,6 +615,7 @@ <h1>Codam Calendar</h1>
530615 state . view = 'agenda' ;
531616 state . agendaStart = date || new Date ( ) ;
532617 state . agendaFocusDate = date || null ;
618+ state . agendaFocusScrolled = false ;
533619 document . querySelectorAll ( '.view-btn' ) . forEach ( b => b . classList . remove ( 'active' ) ) ;
534620 document . querySelector ( '.view-btn[data-view="agenda"]' ) . classList . add ( 'active' ) ;
535621 fetchEvents ( ) ;
@@ -546,6 +632,7 @@ <h1>Codam Calendar</h1>
546632 } else if ( state . view === 'agenda' ) {
547633 state . agendaStart = new Date ( ) ;
548634 state . agendaFocusDate = null ;
635+ state . agendaFocusScrolled = false ;
549636 }
550637 fetchEvents ( ) ;
551638 } ) ;
@@ -752,23 +839,27 @@ <h1>Codam Calendar</h1>
752839 state . agendaStart = new Date ( weekStart ) ;
753840 state . agendaStart . setDate ( state . agendaStart . getDate ( ) - 7 ) ;
754841 state . agendaFocusDate = null ;
842+ state . agendaFocusScrolled = false ;
755843 fetchEvents ( ) ;
756844 } ;
757845 document . getElementById ( 'agendaTodayBtn' ) . onclick = ( ) => {
758846 state . agendaStart = new Date ( ) ;
759847 state . agendaFocusDate = new Date ( ) ;
848+ state . agendaFocusScrolled = false ;
760849 fetchEvents ( ) ;
761850 } ;
762851 document . getElementById ( 'nextWeekBtn' ) . onclick = ( ) => {
763852 state . agendaStart = new Date ( weekStart ) ;
764853 state . agendaStart . setDate ( state . agendaStart . getDate ( ) + 7 ) ;
765854 state . agendaFocusDate = null ;
855+ state . agendaFocusScrolled = false ;
766856 fetchEvents ( ) ;
767857 } ;
768858
769- if ( focusKey ) {
859+ if ( focusKey && ! state . agendaFocusScrolled ) {
770860 const el = document . getElementById ( `day-${ focusKey } ` ) ;
771861 if ( el ) el . scrollIntoView ( { behavior : 'smooth' , block : 'start' } ) ;
862+ state . agendaFocusScrolled = true ;
772863 }
773864 }
774865
@@ -876,10 +967,28 @@ <h1>Codam Calendar</h1>
876967 } else {
877968 renderAgendaView ( eventsByDay ) ;
878969 }
970+
971+ updateScrollTopBtn ( ) ;
972+ }
973+
974+ function updateScrollTopBtn ( ) {
975+ const btn = document . getElementById ( 'scrollTopBtn' ) ;
976+ if ( ! btn ) return ;
977+ const shouldShow = state . view === 'agenda' && window . scrollY > 200 ;
978+ btn . classList . toggle ( 'visible' , shouldShow ) ;
979+ }
980+
981+ function initScrollTopBtn ( ) {
982+ const btn = document . getElementById ( 'scrollTopBtn' ) ;
983+ btn . addEventListener ( 'click' , ( ) => {
984+ window . scrollTo ( { top : 0 , behavior : 'smooth' } ) ;
985+ } ) ;
986+ window . addEventListener ( 'scroll' , updateScrollTopBtn , { passive : true } ) ;
879987 }
880988
881989 initToggles ( ) ;
882990 initViewControls ( ) ;
991+ initScrollTopBtn ( ) ;
883992 fetchEvents ( ) ;
884993 </ script >
885994</ body >
0 commit comments