brutcss/bb/brut/main.clj
Yann Esposito (Yogsototh) 208f4da683
use bb and clojure
2022-10-09 11:03:15 +02:00

472 lines
22 KiB
Clojure
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(ns brut.main
(:require [hiccup2.core :as h]
[clojure.string :as string]
[babashka.fs :as fs]))
(def brutalism-img
"h/img/brutalism.webp")
(defn nav [rel-pref]
(let [to (fn [path] (str rel-pref path))]
[:div
[:nav.nav {:tabindex "-1" :onclick "this.focus()"}
[:div.container
[:a.pagename {:href (to "index.html")} "BRUT"]
[:a {:href (to "h/docs.html")} "Docs"]
[:a {:href (to "h/download.html")} "Download"]
[:a {:href "https://gitea.esy.fun/yogsototh/brutcss"} "Code"]]]
[:button.btn.sn.btn-close "×"]]))
(defn footer []
[:footer
[:div.container
[:p "By "
[:a {:href "https://yannesposito.com"}
"Yann Esposito"]]]])
(defn mk-page [rel-pref metas content]
(let [{:keys [title footer? gapless?]
:or {footer? true
gapless? false}} metas]
(h/html
[:head
[:meta {:http-equiv "Content-Type" :content "text/html; charset=UTF-8"}]
[:meta {:name "viewport" :content "width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no"}]
[:title title]
[:link {:href (str rel-pref "brut.min.css") :rel "stylesheet" :type "text/css"}]]
[(if gapless?
:body.col.gapless
:body.col)
(nav rel-pref)
content
(when footer?
(footer))])))
(defn gen-page [file-path metas content-fn]
(let [{:keys [title]} metas
depth (or (some-> file-path
fs/parent
fs/components
count)
0)
rel-pref (apply str (repeat depth "../"))
html (mk-page rel-pref metas (content-fn rel-pref metas))]
(println "Generates: " file-path)
(spit file-path html)))
(defn mk-index [rel-pref _metas]
(let [to (fn [path] (str rel-pref path))
hero [:div.hero.bg-neutral
[:div.row.middle
[:img.c3.no-grow {:src (to brutalism-img) :alt "brutalism"}]
[:div.col.block.c6
[:h1.title "BRUT"]
[:h4 "A Brutalist and Minimalist CSS Framework"]
[:p (str "This CSS framework is ideal to be used for admin interface where you"
"want to make it clear, this is not for any kind of end user but only"
"advanced technical people.")]]
[:img.c3.no-grow {:src (to brutalism-img) :alt "brutalism"}]
]]
cards [:div.row
[:div.col.card
[:h3 "Docs"]
[:p "Docs"]
[:p "Docs"]
[:a.btn.err.big.push {:href (to "h/docs.html")}
"Docs"]]
[:div.col.card
[:h3 "Download"]
[:div.block
[:p "Download BRUT"]]
[:a.btn.err.big.push {:href (to "h/download.html")}
"Download"]]]]
[:div.container.col
hero
cards]))
(defn mk-download [rel-pref _metas]
(let [to (fn [path] (str rel-pref path))]
[:div.central.fill
{:style (str "background:url('" (to brutalism-img) "')")}
[:a.btn.warn.huge {:href (to "brut.min.css")}
"Download BRUT"]]))
(defn to-pre [hc]
(h/html {:escape-strings? true}
[:pre (-> (str (h/html hc))
(string/replace #"><" ">\n<"))]))
(defn mk-docs [rel-pref _metas]
(let [to (fn [path] (str rel-pref path))
txt
[:div {:id "textual"}
[:h1 "title in h1"]
[:p "Some text in <p> with different styles; "
[:b "bold"]
", " [:strong "strong"]
", " [:i "italic"]
", " [:em "emphasis"]
", " [:code "code"]
", and if you really want something to be extremly visible use the class " [:code.hl "hl"] "."
]
[:p "The text should be " [:strong.hl "very dense"] " on purpose."
" Forget your lessons about nice space in design here."
" The goal of this design is to produce " [:em "professional"] " UI applications."
" So no time to make it breathes."
" We want to make it compact and efficient."]
[:p "Not we still try to keep a coherent and nice vertical rythm."]
[:p "Remark if you need to present a long text to read you can still use the class " [:code "doc"] "."
" Take a look at the next paragraph for example: "]
[:blockquote.doc
"Lorem ipsum with pretty Lorem ipsum dolor sit amet consectetur adipiscing elit, urna consequat felis
vehicula class ultricies mollis dictumst, aenean non a in donec nulla.
Phasellus ante pellentesque erat cum risus consequat imperdiet aliquam, integer
placerat et turpis mi eros nec lobortis taciti, vehicula nisl litora tellus
ligula porttitor metus.
Vivamus integer non suscipit taciti mus etiam at primis tempor sagittis sit,
euismod libero facilisi aptent elementum felis blandit cursus gravida sociis
erat ante, eleifend lectus nullam dapibus netus feugiat curae curabitur est ad.
Massa curae fringilla porttitor quam sollicitudin iaculis aptent leo ligula
euismod dictumst, orci penatibus mauris eros etiam praesent erat volutpat
posuere hac.
Metus fringilla nec ullamcorper odio aliquam lacinia conubia mauris tempor,
etiam ultricies proin quisque lectus sociis id tristique, integer phasellus
taciti pretium adipiscing tortor sagittis ligula.
Mollis pretium lorem primis senectus habitasse lectus scelerisque donec,
ultricies tortor suspendisse adipiscing fusce morbi volutpat pellentesque,
consectetur mi risus molestie curae malesuada cum.
Dignissim lacus convallis massa mauris enim ad mattis magnis senectus montes,
mollis taciti phasellus accumsan bibendum semper blandit suspendisse faucibus
nibh est, metus lobortis morbi cras magna vivamus per risus fermentum.
Dapibus imperdiet praesent magnis ridiculus congue gravida curabitur dictum
sagittis, enim et magna sit inceptos sodales parturient pharetra mollis, aenean
vel nostra tellus commodo pretium sapien sociosqu."]
[:p "The " [:code "doc"] " class ensure the width of the text is not too wide and use a very legible font."]
[:blockquote
"Some blockquote"]
[:h2 "itemization"]
[:h3 "ul"]
[:ul
[:li "item 1"]
[:li "item 2"]
[:li "item 3; with a very long text that should wrap to the next line in any browser."
" We'll see that the wrapped text should be aligned with the text of the other items."
" This is due to the " [:code "list-style-position: outside"] "."
]
[:li "item 4"]]
[:h3 "ol"]
[:ol
[:li "item 1"]
[:li "item 2"]
[:li "item 3"]
[:li "item 4"]]]
images [:div {:id "images"}
[:h1 "Images"]
[:h2 "Inside a grid"]
[:div.row
[:div.card
[:p "Inside a card"]
[:img {:src (to brutalism-img)}]]
[:div
[:p "Directly a card"]
[:img {:src (to brutalism-img)}]]
[:div.block
[:p "In a block"]
[:img {:src (to brutalism-img)}]]]]
buttons [:div {:id "buttons"}
[:h1 "Buttons"]
[:h2 "Text Buttons"]
[:h3 "Classic"]
[:a {:class "tb"} "tb"]
[:a {:class "tb info"} "tb info"]
[:a {:class "tb ok"} "tb ok"]
[:a {:class "tb warn"} "tb warn"]
[:a {:class "tb err"} "tb err"]
[:a {:class "tb fatal"} "tb fatal"]
[:h3 "Sizes"]
[:div {:class "block"} "Text"
[:a {:class "tb sm"} "small"]
[:a {:class "tb"} "normal"]
[:a {:class "tb big"} "Big"]
[:a {:class "tb huge"} "HUGE"]]
[:div {:class "row"}
[:div {:class "col c2 gapless"}
[:span " Text "
[:a {:class "tb sm"} "tb sm"]" "]
[:a {:class "tb sm info"} "tb sm"]
[:a {:class "tb sm ok"} "tb sm"]
[:a {:class "tb sm warn"} "tb sm"]]
[:div {:class "col c2 gapless"}
[:a {:class "tb"} "tb"]
[:a {:class "tb info"} "tb"]
[:a {:class "tb ok"} "tb"]
[:a {:class "tb warn"} "tb"]]
[:div {:class "col c3 gapless"}
[:a {:class "tb big warn"} "tb big"]
[:a {:class "tb big err"} "tb big"]
[:a {:class "tb big fatal"} "tb big"]]
[:div {:class "col c5 gapless"}
[:a {:class "tb huge err"} "tb huge"]
[:a {:class "tb huge fatal"} "tb huge"]]]
[:h2 "Classic"]
[:a {:class "btn"} "btn"]
[:a {:class "btn info"} "btn info"]
[:a {:class "btn ok"} "btn ok"]
[:a {:class "btn warn"} "btn warn"]
[:a {:class "btn err"} "btn err"]
[:a {:class "btn fatal"} "btn fatal"]
[:pre {:class "block"} "&lt;a class=&quot;btn btn-b&quot;&gt;btn-b&lt;/a&gt;"]
[:h2 "Sizes"]
[:a {:class "btn sm"} "btn sm"]
[:a {:class "btn info"} "btn info"]
[:a {:class "btn big warn"} "btn big warn"]
[:a {:class "btn huge err"} "btn huge err"]
[:pre {:class "block"} "&lt;a class=&quot;btn sm info&quot;&gt;btn sm info&lt;/a&gt;"]
[:div {:class "row"}
[:div {:class "col c4 card"}
[:h3 "Standardized Width "
[:code "btn std"]]
[:div {:class "col"}
[:a {:class "btn std"} "btn std"]
[:a {:class "btn std info"} "btn std info"]
[:a {:class "btn std ok"} "btn std ok"]
[:a {:class "btn std warn"} "btn std warn"]
[:a {:class "btn std err"} "btn std err"]
[:a {:class "btn std fatal"} "btn std fatal"]]]
[:div {:class "col c4 card"}
[:h3 "Big"]
[:div {:class "col"}
[:a {:class "btn std big "} "btn std"]
[:a {:class "btn std big info"} "btn std info"]
[:a {:class "btn std big ok"} "btn std ok"]
[:a {:class "btn std big warn"} "btn std warn"]]]
[:div {:class "col c4 card"}
[:h3 "Huge"]
[:div {:class "col"}
[:a {:class "btn std huge"} "btn std"]
[:a {:class "btn std huge info"} "btn std info"]
[:a {:class "btn std huge ok"} "btn std ok"]]]]]
docs [:div
[:h1 "Messages"]
[:div {:class "row"}
[:div {:class "col c6 gapless"}
[:h2 "Basic Messages"]
[:br]
[:div {:class "msg"}
[:strong "Normal Message"]
" This is a normal message with " [:code "msg"] "."]
[:div {:class "msg info"}
[:strong
[:i {:class "ico"} "☞"]" Info"]
" This is done by adding "
[:code "info"]" to the class.\n"]
[:div {:class "msg ok"}
[:strong
[:i {:class "ico"} "☑"]" OK"]
" This is done by adding "
[:code "ok"]" to the class.\n"]
[:div {:class "msg warn"}
[:strong
[:i {:class "ico"} "☣"]" Warning"]
" This is done by adding "
[:code "warn"]" to the class.\n"]
[:div {:class "msg err"}
[:strong
[:i {:class "ico"} "☒"]" Error"]
" This is done by adding "
[:code "err"]" to the class.\n"]
[:div {:class "msg fatal"}
[:strong
[:i {:class "ico"} "☒"]" Fatal"]
" This is done by adding "
[:code "fatal"]" to the class.\n"]]
[:div {:class "col c6 gapless"}
[:h2 "Strong Alerts"]
[:br]
[:div {:class "msg alert"}
[:strong "Alert Message"]"This is a normal message with "
[:code "msg"]".\n"]
[:div {:class "msg alert info"}
[:strong
[:i {:class "ico"} "☞"]" Alert Info"]"This is done by adding "
[:code "info"]" to the class.\n"]
[:div {:class "msg alert ok"}
[:strong
[:i {:class "ico"} "☑"]" Alert OK"]"This is done by adding "
[:code "ok"]" to the class.\n"]
[:div {:class "msg alert warn"}
[:strong
[:i {:class "ico"} "☣"]" Alert Warning"]"This is done by adding "
[:code "warn"]" to the class.\n"]
[:div {:class "msg alert err"}
[:strong
[:i {:class "ico"} "☒"]" Alert Error"]"This is done by adding "
[:code "err"]" to the class.\n"]
[:div {:class "msg alert fatal"}
[:strong
[:i {:class "ico"} "☒"]" Alert Fatal"]"This is done by adding "
[:code "fatal"]" to the class.\n"]]]
[:pre "&lt;div class=&quot;msg&quot;&gt;\n &lt;strong&gt;Alert headline!&lt;/strong&gt;\n Message text\n&lt;/div&gt;"]
[:div
[:h1 "Forms"]
[:input {:class "neutral", :type "text", :placeholder "input"}]
[:br]
[:textarea {:class "neutral", :rows "3", :placeholder "textarea"}]
[:br]
[:span {:class "addon bg-info"} "$"]
[:input {:type "text"}]
[:br]
[:pre "&lt;input type=&quot;text&quot;&gt;\n"
[:br]"&lt;textarea rows=&quot;3&quot;&gt;\n"
[:br]"&lt;span class=&quot;addon&quot;&gt;$&lt;/span&gt;&lt;input type=&quot;text&quot;&gt;"]
[:div {:class "msg"}
[:strong "Be careful with addons!"]" If you do not want a space between the addon and the input make sure that there is no space between the "
[:code "&lt;/span&gt;"]" and "
[:code "&lt;input&gt;"]" tags. Example: "
[:pre "... &lt;/span&gt; &lt;input ..."]
[:span {:class "addon"} "$"]
[:input {:type "text", :class "smooth"}]
[:pre "... &lt;/span&gt;&lt;input ..."]
[:span {:class "addon"} "$"]
[:input {:type "text", :class "smooth"}]]]
[:div {:class "navbar"}
[:h1 "Navbars"]
[:nav {:class "nav", :tabindex "-1", :onclick "this.focus()"}
[:div {:class "container"}
[:a {:class "pagename current", :href "#"} "BRUT"]
[:a {:href "#"} "One"]
[:a {:href "#"} "Two"]
[:a {:href "#"} "Three"]
[:a {:href "#"} "Four"]]]
[:button {:class "btn-close btn sm"} "×"]
[:br]
[:pre "&lt;nav class=&quot;nav&quot; tabindex=&quot;-1&quot; onclick=&quot;this.focus()&quot;&gt;\n &lt;div class=&quot;container&quot;&gt;\n &lt;a class=&quot;pagename current&quot; href=&quot;#&quot;&gt;BRUT&lt;/a&gt;\n &lt;a href=&quot;#&quot;&gt;One&lt;/a&gt;\n &lt;a href=&quot;#&quot;&gt;Two&lt;/a&gt;\n &lt;a href=&quot;#&quot;&gt;Three&lt;/a&gt;\n &lt;/div&gt;\n&lt;/nav&gt;\n&lt;button class=&quot;btn-close btn sm&quot;&gt;×&lt;/button&gt;"]]
[:div
[:h1 "Tables"]
[:table {:class "table"}
[:thead
[:tr
[:th "#"]
[:th "Widgets Sold"]
[:th "Revenue (£)"]
[:th "Profit (£)"]]]
[:tbody
[:tr
[:td "1"]
[:td "5"]
[:td "10"]
[:td "2"]]
[:tr
[:td "2"]
[:td "10"]
[:td "20"]
[:td "4"]]
[:tr
[:td "3"]
[:td "500"]
[:td "1000"]
[:td "200"]]]]
[:br]
[:br]
[:pre "&lt;table class=&quot;table&quot;&gt;\n &lt;thead&gt;\n &lt;tr&gt;\n &lt;th&gt;#&lt;/th&gt;\n &lt;th&gt;Widgets Sold&lt;/th&gt;\n &lt;/tr&gt;\n &lt;/thead&gt;\n &lt;tbody&gt;\n &lt;tr&gt;\n &lt;td&gt;1&lt;/td&gt;\n &lt;td&gt;5&lt;/td&gt;\n &lt;/tr&gt;\n &lt;tr&gt;\n &lt;td&gt;2&lt;/td&gt;\n &lt;td&gt;10&lt;/td&gt;\n &lt;/tr&gt;\n &lt;tr&gt;\n &lt;td&gt;3&lt;/td&gt;\n &lt;td&gt;500&lt;/td&gt;\n &lt;/tr&gt;\n &lt;/tbody&gt;\n&lt;/table&gt;\n"]]
[:h1 "Icons"]
[:div {:class "icons"}
[:div {:class "row"}
[:div {:class "c6"}
[:div {:class "col card"}
[:div {:class "block"}
[:b "Android Safe"]]
[:i {:class "ico block", :style "line-height: 1.5rem"} "☎ ♂ ♀ ⓧ © § ® ⇦ ⇧ ⇨ ⇩♠ ♣ ♥ ♦ ♪ ♛ ♜ ♝ ♞ ♟☜ ☞ ♨ ♭ ♯ ¥£ ¢❊ ฿ ๏ ※ ₧ ₨ ₪ € №\n"]
[:div {:class "msg push"} "The &quot;Android Safe&quot; icons work everywhere, tested on hundreds of devices.\n"]]]
[:div {:class "c6"}
[:div {:class "col card"}
[:div {:class "block"}
[:b "Total Set"]]
[:i {:class "ico block", :style "line-height: 1.5rem"} "✉ ✰ ☁ ✈ ☑ ☒ ✆ ☀ ☮ ☢ ☠ ☣ ⌂ ℗ ☺ ☻ ☼ ∡ ∿ ⊝ ⊘ ⁂ ☤ ♫ ☄ ✎ ☟ ☝ ☹ ☭ ☚ ☛ ✌ 〠 ☃ ♮ ☂ ☸ ✍ ☯ ✂ ₩ ◍ ۩\n"]
[:div {:class "msg warn push"} "Although over 75% of Android devices we tested\nsupport all &quot;Total Set&quot; icons, if a substantial\nportion of your users use old Android devices\nyou should stick to the &quot;Android Safe&quot; set.\n(The &quot;Total Set&quot; does not include icons from the &quot;Android Safe&quot; set.)\n"]]]]
[:pre "&lt;i class=&quot;ico&quot;&gt;Copy and paste icons from above here!&lt;/i&gt;"]
[:h1 "Grids"]
[:div {:class "row"}
[:div {:class "bg-neutral c12"} "c12"]]
[:div {:class "row"}
[:div {:class "bg-neutral c11"} "c11"]
[:div {:class "light c1"} "c1"]]
[:div {:class "row"}
[:div {:class "bg-neutral c10"} "c10"]
[:div {:class "light c2"} "c2"]]
[:div {:class "row"}
[:div {:class "bg-neutral c9"} "c9"]
[:div {:class "light c3"} "c3"]]
[:div {:class "row"}
[:div {:class "bg-neutral c8"} "c8"]
[:div {:class "light c4"} "c4"]]
[:div {:class "row"}
[:div {:class "bg-neutral c7"} "c7"]
[:div {:class "light c5"} "c5"]]
[:div {:class "row"}
[:div {:class "bg-neutral c6"} "c6"]
[:div {:class "light c6"} "c6"]]
[:div {:class "row"}
[:div {:class "bg-neutral c5"} "c5"]
[:div {:class "light c7"} "c7"]]
[:div {:class "row"}
[:div {:class "bg-neutral c4"} "c4"]
[:div {:class "light c8"} "c8"]]
[:div {:class "row"}
[:div {:class "bg-neutral c3"} "c3"]
[:div {:class "light c9"} "c9"]]
[:div {:class "row"}
[:div {:class "bg-neutral c2"} "c2"]
[:div {:class "light c10"} "c10"]]
[:div {:class "row"}
[:div {:class "bg-neutral c1"} "c1"]
[:div {:class "light c11"} "c11"]]
[:div {:class "row"}
[:div {:class "light c12"} "c12"]]
[:br]
[:pre "&lt;div class=&quot;row&quot;&gt;"
[:br]" &lt;div class=&quot;c12&quot;&gt;12&lt;/div&gt;"
[:br]"&lt;/div&gt;\n"
[:br]"&lt;div class=&quot;row&quot;&gt;"
[:br]" &lt;div class=&quot;c4&quot;&gt;4&lt;/div&gt;"
[:br]" &lt;div class=&quot;c8&quot;&gt;8&lt;/div&gt;"
[:br]"&lt;/div&gt;\n"]]
[:h1 "Headings"]
[:div {:class "headings"}
[:p "By default there is some space before and after any heading:"]
[:h1 "h1"]
[:h2 "h2"]
[:h3 "h3"]
[:h4 "h4"]
[:h5 "h5"]
[:h6 "h6"]
[:br]
[:p "You can remove the space by using the class "
[:code "tight"]" to the heading:"]
[:h1 {:class "tight"} "h1 tight"]
[:h2 {:class "tight"} "h2 tight"]
[:h3 {:class "tight"} "h3 tight"]
[:h4 {:class "tight"} "h4 tight"]
[:h5 {:class "tight"} "h5 tight"]
[:h6 {:class "tight"} "h6 tight"]
[:br]
[:pre "&lt;h1&gt;Level One Heading&lt;/h1&gt;"]]]]
[:div.container
(for [b [txt images buttons docs]]
(conj b (to-pre b)))]))
(defn -main [& _args]
(gen-page "index.html"
{:title "BRUT"}
mk-index)
(gen-page "h/download.html"
{:title "BRUT - download"
:footer? false
:gapless? true}
mk-download)
(gen-page "h/g-docs.html"
{:title "BRUT - documentation"}
mk-docs)
)