483 lines
22 KiB
Clojure
483 lines
22 KiB
Clojure
(ns brut.site
|
||
(:require [hiccup2.core :as h]
|
||
[babashka.fs :as fs]
|
||
[babashka.process :refer [process]]))
|
||
|
||
(defn html-pp [html-str]
|
||
(let [xhtml (:out @(process ["tidy" "-i" "-asxhtml" "-quiet" "-utf8"]
|
||
{:in html-str
|
||
:out :string}))]
|
||
(:out @(process ["hxselect" "-c" "body"]
|
||
{:in xhtml
|
||
:out :string}))))
|
||
|
||
(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 [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))
|
||
html-pp)]))
|
||
|
||
(defn mk-docs [rel-pref _metas]
|
||
(let [to (fn [path] (str rel-pref path))
|
||
txt [:div {:id "text"}
|
||
[: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 "Note we still try to keep a coherent and nice vertical rythm."]
|
||
[:blockquote
|
||
[:p "Here is some blockquote."
|
||
" This can give you an idea about the look and feel for them."]]]
|
||
doc [:div {:id "doc"}
|
||
[: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: "]
|
||
[:div.doc
|
||
[:p
|
||
"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."]
|
||
[:p
|
||
"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."]]
|
||
[:p "The " [:code "doc"] " class ensure the width of the text is not too wide and use a very legible font."]]
|
||
itemize [:div {:id "itemize"}
|
||
[: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"]]]
|
||
headings [:div
|
||
[:h3 "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"]
|
||
[:h3 "tight headings"]
|
||
[: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"]]
|
||
textual-section {:title "Textual content"
|
||
:cards [txt doc headings itemize]}
|
||
|
||
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)}]]]]
|
||
images-section {:title "Images"
|
||
:cards [images]}
|
||
text-buttons [:div#text-buttons
|
||
[:h3 "Classic"]
|
||
[:a.tb "tb"]
|
||
[:a.tb.info "tb info"]
|
||
[:a.tb.ok "tb ok"]
|
||
[:a.tb.warn "tb warn"]
|
||
[:a.tb.err "tb err"]
|
||
[:a.tb.fatal "tb fatal"]]
|
||
text-buttons-sizes [:div#text-buttons-sizes
|
||
[:h3 "Sizes"]
|
||
[:h4 "Inside some text"]
|
||
[:div.block "Some text: "
|
||
[:a {:class "tb sm info"} "Info"]
|
||
[:a {:class "tb ok"} "OK"]
|
||
[:a {:class "tb big warn"} "Warn"]
|
||
[:a {:class "tb huge err"} "ERR"]]
|
||
[:h4 "In a grid"]
|
||
[:div.row.gapless
|
||
[:div.col.c2.gapless
|
||
[: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.col.c2.gapless
|
||
[:a {:class "tb"} "tb"]
|
||
[:a {:class "tb info"} "tb"]
|
||
[:a {:class "tb ok"} "tb"]
|
||
[:a {:class "tb warn"} "tb"]]
|
||
[:div.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.col.c5.gapless
|
||
[:a {:class "tb huge err"} "tb huge"]
|
||
[:a {:class "tb huge fatal"} "tb huge"]]]]
|
||
buttons [:div {:id "buttons"}
|
||
[: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"} "<a class="btn btn-b">btn-b</a>"]
|
||
[: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"} "<a class="btn sm info">btn sm info</a>"]
|
||
[: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"]]]]]
|
||
buttons-section {:title "Buttons"
|
||
:cards [text-buttons text-buttons-sizes buttons]}
|
||
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"]]]
|
||
messages-section {:title "Messages"
|
||
:cards [messages]}
|
||
forms [:div
|
||
[:input {:class "neutral", :type "text", :placeholder "input"}]
|
||
[:br]
|
||
[:textarea {:class "neutral", :rows "3", :placeholder "textarea"}]
|
||
[:br]
|
||
[:span {:class "addon bg-info"} "$"]
|
||
[:input {:type "text"}]
|
||
[: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 "<span>"] " and "
|
||
[:code "<input>"]" tags. Example: "
|
||
[:pre "... </span>" [:span.hl " "] "<input ..."]
|
||
[:span {:class "addon"} "$"] " "
|
||
[:input {:type "text", :class "smooth"}]
|
||
[:pre "... </span><input ..."]
|
||
[:span {:class "addon"} "$"]
|
||
[:input {:type "text", :class "smooth"}]]]
|
||
forms-section {:title "Forms"
|
||
:cards [forms]}
|
||
navbar [:div {:class "navbar"}
|
||
[: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"} "×"]]
|
||
navbar-section {:title "Navbar"
|
||
:cards [navbar]
|
||
}
|
||
table [: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"]]]]
|
||
tables-section {:title "Tables"
|
||
:cards [table]}
|
||
basic-icons [:div.col.start
|
||
[:h4 "Android Safe"]
|
||
[:i {:class "ico block", :style "line-height: 1.5rem"} "☎ ♂ ♀ ⓧ © § ® ⇦ ⇧ ⇨ ⇩♠ ♣ ♥ ♦ ♪ ♛ ♜ ♝ ♞ ♟☜ ☞ ♨ ♭ ♯ ¥£ ¢❊ ฿ ๏ ※ ₧ ₨ ₪ € №\n"]
|
||
[:div {:class "msg push"} "The "Android Safe" icons work everywhere, tested on hundreds of devices.\n"]]
|
||
full-icons [:div.col.start
|
||
[:h4 "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 "Total Set" icons, if a substantial\nportion of your users use old Android devices\nyou should stick to the "Android Safe" set.\n(The "Total Set" does not include icons from the "Android Safe" set.)\n"]]
|
||
icons-section {:title "icons"
|
||
:cards [basic-icons full-icons]}
|
||
grid [:div
|
||
[: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"]]]
|
||
grid-section {:title "Grid"
|
||
:cards [grid]}]
|
||
[:div.container
|
||
(for [{:keys [title cards]} [textual-section
|
||
grid-section
|
||
images-section
|
||
icons-section
|
||
forms-section
|
||
tables-section
|
||
buttons-section
|
||
messages-section
|
||
navbar-section]]
|
||
[:div.col
|
||
[:h2 title]
|
||
(for [[c1 c2] (partition 2 2 nil cards)]
|
||
[:div.row
|
||
[:div.card.c6
|
||
c1
|
||
[:details
|
||
[:summary "code"]
|
||
(to-pre c1)]]
|
||
(when c2
|
||
[:div.card.c6
|
||
c2
|
||
[:details
|
||
[:summary "code"]
|
||
(to-pre c2)]])])])]))
|
||
|
||
(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/docs.html"
|
||
{:title "BRUT - documentation"}
|
||
mk-docs)
|
||
)
|