494 lines
21 KiB
Clojure
494 lines
21 KiB
Clojure
(ns brut.site
|
||
(:require [hiccup2.core :as h]
|
||
[babashka.fs :as fs]
|
||
[clojure.string :as string]
|
||
[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.big.push {:href (to "h/docs.html")}
|
||
"Docs"]]
|
||
[:div.col.card
|
||
[:h3 "Download"]
|
||
[:div.block
|
||
[:p "Download BRUT"]]
|
||
[:a.btn.warn.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"] ". "
|
||
"If you really want something to be extremly visible, "
|
||
[:strong.hl "use the class "[:code.hl "hl"]]
|
||
"."]
|
||
[:p "Links will looks like this into text: "
|
||
[:a {:href "#"} "This is a link inside a paragraph."]]
|
||
[: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.block
|
||
[:p "In a block"]
|
||
[:img {:src (to brutalism-img)}]]
|
||
[:div
|
||
[:span "Directly in the column"]
|
||
[:img {:src (to brutalism-img)}]]
|
||
]]
|
||
images-section {:title "Images"
|
||
:cards [images]}
|
||
text-buttons [:div#text-buttons
|
||
[:h3 "Textual buttons"]
|
||
[: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 "Textual Buttons Sizes"]
|
||
[:div.block
|
||
"Some text: " [:a {:class "tb sm info"} "small button"] [:br]
|
||
"Some text: " [:a {:class "tb ok"} "normal ok"] [:br]
|
||
"Some text: " [:a {:class "tb big warn"} "big warn"] [:br]
|
||
"Some text: " [:a {:class "tb huge err"} "huge err"]]]
|
||
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"]]]]]
|
||
tags [:div {:id "tags"}
|
||
[:h2 "Tags"]
|
||
[:ul
|
||
[:li "item-1" [:span.tag "tag"]]
|
||
[:li "item-2" [:span.tag.info "info"]]
|
||
[:li "item-3" [:span.tag.ok "ok"]]
|
||
[:li "item-4" [:span.tag.warn "warn"]]
|
||
[:li "item-5" [:span.tag.err "err"]]
|
||
[:li "item-6" [:span.tag.fatal "fatal"]]]]
|
||
tags-listed [:div {:id "tags-inline"}
|
||
[:h2 "Inline Tags"]
|
||
[:span.tag "tag"]
|
||
[:span.tag.hl "tag hl"]
|
||
[:span.tag.info "info"]
|
||
[:span.tag.ok "ok"]
|
||
[:span.tag.warn "warn"]
|
||
[:span.tag.err "err"]
|
||
[:span.tag.fatal "fatal"]
|
||
]
|
||
buttons-section {:title "Buttons"
|
||
:cards [tags tags-listed
|
||
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.ico.big "☞"]" Info"]
|
||
" This is done by adding "
|
||
[:code "info"]" to the class.\n"]
|
||
[:div {:class "msg ok"}
|
||
[:strong
|
||
[:i.ico.big "☑"]" OK"]
|
||
" This is done by adding "
|
||
[:code "ok"]" to the class.\n"]
|
||
[:div {:class "msg warn"}
|
||
[:strong
|
||
[:i.ico.big "☣"]" Warning"]
|
||
" This is done by adding "
|
||
[:code "warn"]" to the class.\n"]
|
||
[:div {:class "msg err"}
|
||
[:strong
|
||
[:i.ico.big "☒"]" Error"]
|
||
" This is done by adding "
|
||
[:code "err"]" to the class.\n"]
|
||
[:div {:class "msg fatal"}
|
||
[:strong
|
||
[:i.ico.big "☠"]" Fatal"]
|
||
" This is done by adding "
|
||
[:code "fatal"]" to the class.\n"]
|
||
[:div {:class "msg hl"}
|
||
[:strong
|
||
[:i.ico.big "☞"] "Highlighted"]
|
||
" This is done by adding "
|
||
[:code "hl"]" 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]}
|
||
footer [:footer
|
||
[:div.container
|
||
[:p "Made by " [:a {:href "https://yannesposito.com"} "Yann Esposito"]]]]
|
||
footer-section {:title "Footer"
|
||
:cards [footer]}
|
||
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 "Safe"]
|
||
[:i {:class "ico block big"} "☎ ♂ ♀ ⓧ © § ® ⇦ ⇧ ⇨ ⇩♠ ♣ ♥ ♦ ♪ ♛ ♜ ♝ ♞ ♟☜ ☞ ♨ ♭ ♯ ¥£ ¢❊ ฿ ๏ ※ ₧ ₨ ₪ € №\n"]
|
||
[:div {:class "msg push"}
|
||
[:p
|
||
"The \"Safe\" icons should work almost everywhere."]
|
||
[:p
|
||
(mapcat (fn [w i]
|
||
[ [:span w " "] [:i.ico i] " "])
|
||
(string/split
|
||
(str "Inserting in the middle of some text to check the size."
|
||
" Now this should give an idea about the size relatively "
|
||
"to the text. Hmmm this is quite long and boring to write"
|
||
" text in between like that!")
|
||
#" ")
|
||
|
||
(string/split "☎♂♀ⓧ©§®⇦⇧⇨⇩♠♣♥♦♪♛♜♝♞♟☜☞♨♭♯¥£¢❊฿๏※₧₨₪€№" #""))
|
||
]]]
|
||
full-icons [:div.col.start
|
||
[:h4 "Total Set"]
|
||
[:i {:class "ico block big"}
|
||
"✉ ✰ ☁ ✈ ☑ ☒ ✆ ☀ ☮ ☢ ☠ ☣ ⌂ ℗ ☺ ☻ ☼ ∡ ∿ ⊝ ⊘ ⁂ ☤ ♫ ☄ ✎ ☟ ☝ ☹ ☭ ☚ ☛ ✌ 〠 ☃ ♮ ☂ ☸ ✍ ☯ ✂ ₩ ◍ ۩\n"]
|
||
[:div.msg "Just a bunch of a few more unicode icons."]]
|
||
icons-section {:title "icons"
|
||
:cards [basic-icons full-icons]}
|
||
grid
|
||
[:div
|
||
[:h3 "With default gap"]
|
||
[:div
|
||
(for [i (range 12 -1 -1)]
|
||
(let [cl (str "c" i)
|
||
co-cl (str "c" (- 12 i))]
|
||
[:div.row
|
||
(when (> i 0)
|
||
[:div.bg-neutral {:class cl} cl])
|
||
(when (> (- 12 i) 0)
|
||
[:div.y {:class co-cl} co-cl])]))]]
|
||
grid-gapless
|
||
[:div
|
||
[:h3 "Gapless"]
|
||
[:div
|
||
(for [i (range 12 -1 -1)]
|
||
(let [cl (str "c" i)
|
||
co-cl (str "c" (- 12 i))]
|
||
[:div.row.gapless
|
||
(when (> i 0)
|
||
[:div.bg-neutral {:class cl} cl])
|
||
(when (> (- 12 i) 0)
|
||
[:div.y {:class co-cl} co-cl])]))]]
|
||
grid-3col
|
||
[:div
|
||
[:h3 "3 columns"]
|
||
[:div
|
||
(for [i (range 11 0 -1)
|
||
j (range (- 11 i) -1 -1)]
|
||
(let [k (- 12 i j)
|
||
cli (str "c" i)
|
||
clj (str "c" j)
|
||
clk (str "c" k)]
|
||
(if (= j 0)
|
||
[:br]
|
||
[:div.row
|
||
(when (> j 0)
|
||
[:div.b {:class clj} clj])
|
||
(when (> i 0)
|
||
[:div.bg-neutral {:class cli} cli])
|
||
(when (> k 0)
|
||
[:div.r {:class clk} clk])
|
||
])))]]
|
||
grid-section {:title "Grid"
|
||
:cards [grid grid-gapless grid-3col]}]
|
||
[:div.container
|
||
(for [{:keys [title cards]} [textual-section
|
||
grid-section
|
||
images-section
|
||
icons-section
|
||
forms-section
|
||
tables-section
|
||
buttons-section
|
||
messages-section
|
||
navbar-section
|
||
footer-section]]
|
||
[:div.col
|
||
[:h2 {:id title}
|
||
[:a {:href (str "#" title)} [:i.ico "§"]] " "
|
||
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)
|
||
)
|