diff --git a/src/component/accordion.lisp b/src/component/accordion.lisp index 8931449..3c31532 100644 --- a/src/component/accordion.lisp +++ b/src/component/accordion.lisp @@ -18,23 +18,27 @@ ID: Specifies a unique identifier for the accordion. Defaults to 'accordionExamp FLUSH: If t, adds class 'accordion-flush' to remove borders. Defaults to nil. +BODY: Sequence of strings where every pair represents a title and content for +the accordion item. + --- 5 Scenarios to Avoid Them: https://www.nngroup.com/videos/avoid-accordions/ --- Example usage: - (accordion () (\"Title 1\" \"Content 1\") (\"Title 2\" \"Content 2\")) - (accordion (:id \"accordionExample\" :flush t) (\"Title 1\" \"Content 1\") (\"Title 2\" \"Content 2\"))" - (let ((class (concatenate 'string "accordion" (when flush " accordion-flush")))) + (accordion () \"Title 1\" \"Content 1\" \"Title 2\" \"Content 2\")" + (let ((class (if flush "accordion accordion-flush" "accordion"))) `(spinneret:with-html (:div :class ,class :id ,id - ,@(loop for (title content) in body + ,@(loop for (title content) on body by #'cddr for counter from 1 for collapse-id = (format nil "collapse-~a-~a" id counter) + for collapse-class = (concatenate 'string "accordion-collapse collapse" (when (= counter 1) " show")) + for btn-class = (concatenate 'string "accordion-button" (when (not (= counter 1)) " collapsed")) collect `(:div :class "accordion-item" (:h2 :class "accordion-header" - (:button :class "accordion-button" + (:button :class ,btn-class :type "button" :data-bs-toggle "collapse" :data-bs-target ,(concatenate 'string "#" collapse-id) @@ -42,7 +46,7 @@ Example usage: :aria-controls ,collapse-id ,title)) (:div :id ,collapse-id - :class "accordion-collapse collapse" + :class ,collapse-class :data-bs-parent ,(concatenate 'string "#" id) (:div :class "accordion-body" ,content)))))))) diff --git a/tests/component/accordion.lisp b/tests/component/accordion.lisp index 0a14665..9b8b92d 100644 --- a/tests/component/accordion.lisp +++ b/tests/component/accordion.lisp @@ -5,45 +5,12 @@ :rove) (:import-from :dev.metalisp.sbt/component/accordion - :header - :collapse - :item :accordion)) (in-package :dev.metalisp.sbt/tests/accordion) -(deftest test-header - (let ((result (spinneret:with-html-string (header "collapseOne" "Heading" t)))) - (testing "Generates correct HTML for accordion header" - (ok (search "class=accordion-header" result)) - (ok (search "class=accordion-button" result)) - (ok (search "data-bs-target=#collapseOne" result)) - (ok (search "aria-expanded=true" result)) - (ok (search "aria-controls=#collapseOne" result)) - (ok (search "Heading" result))))) - -(deftest test-collapse - (let ((result (spinneret:with-html-string (collapse "accordionExample" "collapseOne" t)))) - (testing "Generates correct HTML for accordion collapse" - (ok (search "class=\"accordion-collapse collapse show\"" result)) - (ok (search "id=collapseOne" result)) - (ok (search "data-bs-parent=#accordionExample" result)) - (ok (search "class=accordion-body" result))))) - -(deftest test-item - (let ((result (spinneret:with-html-string (item (header "collapseOne" "Heading" t) (collapse "accordionExample" "collapseOne" t "Some content"))))) - (testing "Generates correct HTML for accordion item" - (ok (search "class=accordion-item" result)) - (ok (search "class=accordion-header" result)) - (ok (search "class=accordion-button" result)) - (ok (search "class=\"accordion-collapse collapse show\"" result)) - (ok (search "data-bs-target=#collapseOne" result)) - (ok (search "aria-expanded=true" result)) - (ok (search "aria-controls=#collapseOne" result)) - (ok (search "Some content" result))))) - (deftest test-accordion-correct-classes - (let ((result (with-output-to-string (spinneret:*html*) (accordion (:id "accordionExample" :flush t) ("Accordion Item #1" "Accordion Content #1") ("Accordion Item #2" "Accordion Content #2") ("Accordion Item #3" "Accordion Content #3"))))) + (let ((result (with-output-to-string (spinneret:*html*) (accordion (:id "accordionExample" :flush t) "Accordion Item #1" "Accordion Content #1" "Accordion Item #2" "Accordion Content #2" "Accordion Item #3" "Accordion Content #3")))) (testing "Generates correct HTML for accordion" (ok (search "class=accordion" result)) (ok (search "class=accordion-item" result)) @@ -51,14 +18,14 @@ (ok (search "class=accordion-button" result))))) (deftest test-accordion-correct-id - (let ((result (with-output-to-string (spinneret:*html*) (accordion (:id "accordionExample" :flush t) ("Accordion Item #1" "Accordion Content #1") ("Accordion Item #2" "Accordion Content #2") ("Accordion Item #3" "Accordion Content #3"))))) + (let ((result (with-output-to-string (spinneret:*html*) (accordion (:id "accordionExample" :flush t) "Accordion Item #1" "Accordion Content #1" "Accordion Item #2" "Accordion Content #2" "Accordion Item #3" "Accordion Content #3")))) (testing "Generates correct HTML for accordion" (ok (search "id=accordionExample" result)) (ok (search "id=collapse-accordionExample-1" result)) (ok (search "id=collapse-accordionExample-2" result))))) (deftest test-accordion-correct-aria - (let ((result (with-output-to-string (spinneret:*html*) (accordion (:id "accordionExample" :flush t) ("Accordion Item #1" "Accordion Content #1") ("Accordion Item #2" "Accordion Content #2") ("Accordion Item #3" "Accordion Content #3"))))) + (let ((result (with-output-to-string (spinneret:*html*) (accordion (:id "accordionExample" :flush t) "Accordion Item #1" "Accordion Content #1" "Accordion Item #2" "Accordion Content #2" "Accordion Item #3" "Accordion Content #3")))) (testing "Generates correct HTML for accordion" (ok (search "aria-expanded=true" result)) (ok (search "aria-expanded=false" result))