Skip to content

Commit deebe80

Browse files
committed
Allow navigation via keyboard
1 parent 519c827 commit deebe80

File tree

1 file changed

+153
-128
lines changed

1 file changed

+153
-128
lines changed

src/scittle/conj_2025/trivia_slideshow.cljs

Lines changed: 153 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -874,154 +874,179 @@
874874
"Simple slideshow viewer without game mechanics"
875875
[]
876876
(let [lightbox-open? (r/atom false)]
877-
(fn []
878-
(let [{:keys [current-slide]} @game-state
879-
{:keys [image]} (current-slide-data)]
880-
[:div {:class "trivia-container"}
881-
;; Lightbox overlay
882-
(when @lightbox-open?
883-
[:div {:style {:position "fixed"
884-
:top 0
885-
:left 0
886-
:right 0
887-
:bottom 0
888-
:background "rgba(0,0,0,0.95)"
889-
:z-index 9999
890-
:display "flex"
891-
:align-items "center"
892-
:justify-content "center"
893-
:cursor "pointer"
894-
:animation "fadeIn 0.2s ease"}
895-
:on-click #(reset! lightbox-open? false)}
896-
[:div {:style {:position "relative"
897-
:max-width "95vw"
898-
:max-height "95vh"}}
899-
[:img {:src image
900-
:alt "Conference photo - full size"
901-
:style {:max-width "95vw"
902-
:max-height "95vh"
903-
:object-fit "contain"
904-
:image-orientation "from-image"}}]
905-
[:div {:style {:position "absolute"
906-
:top "10px"
907-
:right "10px"
908-
:background "rgba(255,255,255,0.9)"
909-
:color "#333"
910-
:border "none"
911-
:border-radius "50%"
912-
:width "40px"
913-
:height "40px"
877+
(r/create-class
878+
{:component-did-mount
879+
(fn [this]
880+
(let [handle-key (fn [e]
881+
(let [key (.-key e)]
882+
(case key
883+
"ArrowLeft" (do (.preventDefault e)
884+
(when (> (:current-slide @game-state) 0)
885+
(previous-slide)))
886+
"ArrowRight" (do (.preventDefault e)
887+
(when (< (:current-slide @game-state) (dec (total-slides)))
888+
(next-slide)))
889+
"Escape" (when @lightbox-open?
890+
(.preventDefault e)
891+
(reset! lightbox-open? false))
892+
nil)))]
893+
(js/document.addEventListener "keydown" handle-key)
894+
(aset this "keyHandler" handle-key)))
895+
896+
:component-will-unmount
897+
(fn [this]
898+
(when-let [handler (aget this "keyHandler")]
899+
(js/document.removeEventListener "keydown" handler)))
900+
901+
:reagent-render
902+
(fn []
903+
(let [{:keys [current-slide]} @game-state
904+
{:keys [image]} (current-slide-data)]
905+
[:div {:class "trivia-container"}
906+
;; Lightbox overlay
907+
(when @lightbox-open?
908+
[:div {:style {:position "fixed"
909+
:top 0
910+
:left 0
911+
:right 0
912+
:bottom 0
913+
:background "rgba(0,0,0,0.95)"
914+
:z-index 9999
914915
:display "flex"
915916
:align-items "center"
916917
:justify-content "center"
917-
:font-size "24px"
918918
:cursor "pointer"
919-
:font-weight "bold"}}
920-
"×"]]])
921-
922-
;; Title
923-
[:div {:style {:text-align "center"
924-
:margin-bottom "30px"}}
925-
[:h1 {:class "game-title"
926-
:style {:color "#2196f3"
927-
:font-size "32px"
928-
:margin-bottom "10px"}}
929-
"🖼️ Clojure Conj 2025 Photo Gallery"]
930-
[:p {:class "game-subtitle"
931-
:style {:color "#666"
932-
:font-size "16px"}}
933-
"Browse through conference memories"]]
934-
935-
[:div {:class "trivia-card"}
936-
;; Image section - full width
937-
[:div {:style {:display "flex"
938-
:align-items "center"
939-
:justify-content "center"
940-
:padding "40px"
941-
:min-height "500px"}}
942-
[:img {:src image
943-
:alt "Conference photo"
944-
:on-click #(reset! lightbox-open? true)
945-
:style {:max-width "100%"
946-
:max-height "600px"
947-
:border-radius "12px"
948-
:box-shadow "0 4px 12px rgba(0,0,0,0.15)"
949-
:object-fit "contain"
950-
:image-orientation "from-image"
951-
:cursor "pointer"
952-
:transition "transform 0.2s ease, box-shadow 0.2s ease"}
953-
:on-mouse-enter #(do
954-
(set! (.. % -target -style -transform) "scale(1.02)")
955-
(set! (.. % -target -style -boxShadow) "0 8px 24px rgba(0,0,0,0.25)"))
956-
:on-mouse-leave #(do
957-
(set! (.. % -target -style -transform) "scale(1)")
958-
(set! (.. % -target -style -boxShadow) "0 4px 12px rgba(0,0,0,0.15)"))}]]
959-
960-
;; Navigation
961-
[:div {:class "trivia-nav"
962-
:style {:padding "20px"
963-
:border-top "1px solid #e0e0e0"}}
964-
[:div {:style {:text-align "center"
965-
:margin-bottom "15px"}}
966-
[:p {:class "trivia-slide-info"}
967-
(str "Photo " (inc current-slide) " of " (total-slides))]
968-
[:p {:style {:margin "5px 0 0 0"
969-
:font-size "13px"
970-
:color "#999"
971-
:font-style "italic"}}
972-
"Click image to view full size"]]
973-
974-
[:div {:style {:display "flex"
975-
:justify-content "space-between"
976-
:gap "15px"}}
977-
[:button {:on-click previous-slide
978-
:disabled (= current-slide 0)
979-
:style {:padding "12px 24px"
980-
:background (if (= current-slide 0) "#e0e0e0" "#2196f3")
981-
:color (if (= current-slide 0) "#999" "white")
919+
:animation "fadeIn 0.2s ease"}
920+
:on-click #(reset! lightbox-open? false)}
921+
[:div {:style {:position "relative"
922+
:max-width "95vw"
923+
:max-height "95vh"}}
924+
[:img {:src image
925+
:alt "Conference photo - full size"
926+
:style {:max-width "95vw"
927+
:max-height "95vh"
928+
:object-fit "contain"
929+
:image-orientation "from-image"}}]
930+
[:div {:style {:position "absolute"
931+
:top "10px"
932+
:right "10px"
933+
:background "rgba(255,255,255,0.9)"
934+
:color "#333"
982935
:border "none"
983-
:border-radius "6px"
984-
:cursor (if (= current-slide 0) "not-allowed" "pointer")
985-
:font-weight "600"
986-
:font-size "16px"
987-
:flex "1"}}
988-
"← Previous"]
989-
990-
[:button {:on-click back-to-menu
991-
:style {:padding "12px 24px"
992-
:background "#757575"
993-
:color "white"
994-
:border "none"
995-
:border-radius "6px"
936+
:border-radius "50%"
937+
:width "40px"
938+
:height "40px"
939+
:display "flex"
940+
:align-items "center"
941+
:justify-content "center"
942+
:font-size "24px"
996943
:cursor "pointer"
997-
:font-weight "600"
998-
:font-size "16px"
999-
:flex "0 0 auto"}}
1000-
"🏠 Menu"]
944+
:font-weight "bold"}}
945+
"×"]]])
1001946

1002-
(if (= current-slide (dec (total-slides)))
1003-
[:button {:on-click back-to-menu
947+
;; Title
948+
[:div {:style {:text-align "center"
949+
:margin-bottom "30px"}}
950+
[:h1 {:class "game-title"
951+
:style {:color "#2196f3"
952+
:font-size "32px"
953+
:margin-bottom "10px"}}
954+
"🖼️ Clojure Conj 2025 Photo Gallery"]
955+
[:p {:class "game-subtitle"
956+
:style {:color "#666"
957+
:font-size "16px"}}
958+
"Browse through conference memories"]]
959+
960+
[:div {:class "trivia-card"}
961+
;; Image section - full width
962+
[:div {:style {:display "flex"
963+
:align-items "center"
964+
:justify-content "center"
965+
:padding "40px"
966+
:min-height "500px"}}
967+
[:img {:src image
968+
:alt "Conference photo"
969+
:on-click #(reset! lightbox-open? true)
970+
:style {:max-width "100%"
971+
:max-height "600px"
972+
:border-radius "12px"
973+
:box-shadow "0 4px 12px rgba(0,0,0,0.15)"
974+
:object-fit "contain"
975+
:image-orientation "from-image"
976+
:cursor "pointer"
977+
:transition "transform 0.2s ease, box-shadow 0.2s ease"}
978+
:on-mouse-enter #(do
979+
(set! (.. % -target -style -transform) "scale(1.02)")
980+
(set! (.. % -target -style -boxShadow) "0 8px 24px rgba(0,0,0,0.25)"))
981+
:on-mouse-leave #(do
982+
(set! (.. % -target -style -transform) "scale(1)")
983+
(set! (.. % -target -style -boxShadow) "0 4px 12px rgba(0,0,0,0.15)"))}]]
984+
985+
;; Navigation
986+
[:div {:class "trivia-nav"
987+
:style {:padding "20px"
988+
:border-top "1px solid #e0e0e0"}}
989+
[:div {:style {:text-align "center"
990+
:margin-bottom "15px"}}
991+
[:p {:class "trivia-slide-info"}
992+
(str "Photo " (inc current-slide) " of " (total-slides))]
993+
[:p {:style {:margin "5px 0 0 0"
994+
:font-size "13px"
995+
:color "#999"
996+
:font-style "italic"}}
997+
"Click image to view full size • Use ← → arrow keys to navigate"]]
998+
999+
[:div {:style {:display "flex"
1000+
:justify-content "space-between"
1001+
:gap "15px"}}
1002+
[:button {:on-click previous-slide
1003+
:disabled (= current-slide 0)
10041004
:style {:padding "12px 24px"
1005-
:background "#4caf50"
1006-
:color "white"
1005+
:background (if (= current-slide 0) "#e0e0e0" "#2196f3")
1006+
:color (if (= current-slide 0) "#999" "white")
10071007
:border "none"
10081008
:border-radius "6px"
1009-
:cursor "pointer"
1009+
:cursor (if (= current-slide 0) "not-allowed" "pointer")
10101010
:font-weight "600"
10111011
:font-size "16px"
10121012
:flex "1"}}
1013-
"✓ Finish"]
1014-
[:button {:on-click next-slide
1013+
"← Previous"]
1014+
1015+
[:button {:on-click back-to-menu
10151016
:style {:padding "12px 24px"
1016-
:background "#2196f3"
1017+
:background "#757575"
10171018
:color "white"
10181019
:border "none"
10191020
:border-radius "6px"
10201021
:cursor "pointer"
10211022
:font-weight "600"
10221023
:font-size "16px"
1023-
:flex "1"}}
1024-
"Next →"])]]]]))))
1024+
:flex "0 0 auto"}}
1025+
"🏠 Menu"]
1026+
1027+
(if (= current-slide (dec (total-slides)))
1028+
[:button {:on-click back-to-menu
1029+
:style {:padding "12px 24px"
1030+
:background "#4caf50"
1031+
:color "white"
1032+
:border "none"
1033+
:border-radius "6px"
1034+
:cursor "pointer"
1035+
:font-weight "600"
1036+
:font-size "16px"
1037+
:flex "1"}}
1038+
"✓ Finish"]
1039+
[:button {:on-click next-slide
1040+
:style {:padding "12px 24px"
1041+
:background "#2196f3"
1042+
:color "white"
1043+
:border "none"
1044+
:border-radius "6px"
1045+
:cursor "pointer"
1046+
:font-weight "600"
1047+
:font-size "16px"
1048+
:flex "1"}}
1049+
"Next →"])]]]]))})))
10251050

10261051
;; ============================================================================
10271052
;; Main Component

0 commit comments

Comments
 (0)