├── .editorconfig ├── .gitignore ├── 00-old ├── flakes │ └── example.flakes ├── project.clj └── src-cljs │ ├── client │ └── com │ │ └── oakmac │ │ └── snowflake │ │ └── client │ │ ├── core.cljs │ │ └── util.cljs │ └── server │ └── com │ └── oakmac │ └── snowflake │ └── server │ ├── config.cljs │ ├── core.cljs │ └── util.cljs ├── 00-scrap ├── css-application.png ├── notes.md ├── snowflake-application.png ├── snowflake-logo.png └── ui-mockup.png ├── LICENSE.md ├── README.md ├── bin └── snowflake-css.js ├── example ├── everything.css ├── main.css └── templates │ ├── about-us.html │ └── index.html ├── package.json ├── public ├── css │ └── main.css ├── fonts │ ├── DroidSansMono.woff2 │ ├── OpenSans-Light.woff │ ├── OpenSans-Semibold.woff │ └── OpenSans.woff └── index.html ├── shadow-cljs.edn ├── snowflake-css.json ├── src-cljs └── snowflake_css │ ├── cli │ └── core.cljs │ └── lib │ ├── filesystem_helpers.cljs │ ├── flake_parsing.cljs │ ├── logging.cljs │ ├── node_helpers.cljs │ └── predicates.cljs └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs. 2 | # More information at http://EditorConfig.org 3 | 4 | # Do not check for any .editorconfig files above this directory 5 | root = true 6 | 7 | # All files 8 | [*] 9 | charset = utf-8 10 | end_of_line = lf 11 | indent_size = 2 12 | indent_style = space 13 | insert_final_newline = true 14 | trim_trailing_whitespace = true 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .shadow-cljs/ 3 | 4 | *.diff 5 | *.tgz 6 | -------------------------------------------------------------------------------- /00-old/flakes/example.flakes: -------------------------------------------------------------------------------- 1 | ===== Variables 2 | 3 | ===== Mixins 4 | 5 | ===== Classes 6 | 7 | foo-1205c 8 | border 1px solid blue 9 | padding 20px 10 | position relative 11 | 12 | bar-a1f63 13 | display inline-block 14 | margin 0 10px 15 | padding 5px 16 | -------------------------------------------------------------------------------- /00-old/project.clj: -------------------------------------------------------------------------------- 1 | (defproject snowflake "0.1.0" 2 | :description "Snowflake CSS Server and Tooling" 3 | :url "https://github.com/oakmac/snowflake-css" 4 | 5 | :license {:name "ISC License" 6 | :url "https://github.com/oakmac/snowflake-css/blob/master/LICENSE.md" 7 | :distribution :repo} 8 | 9 | :dependencies [[org.clojure/clojure "1.8.0"] 10 | [org.clojure/clojurescript "1.9.946"] 11 | [com.cognitect/transit-cljs "0.8.239"] 12 | [com.oakmac/util "2.0.1"] 13 | [rum "0.10.8"]] 14 | 15 | :plugins [[lein-cljsbuild "1.1.7"]] 16 | 17 | :source-paths ["src"] 18 | 19 | :clean-targets ["app.js" 20 | "public/js/app-dev.js" 21 | "public/js/app-prod.js" 22 | "target"] 23 | 24 | :cljsbuild 25 | {:builds 26 | [{:id "client-dev" 27 | :source-paths ["src-cljs/client"] 28 | :compiler {:optimizations :whitespace 29 | :output-to "public/js/app-dev.js"}} 30 | 31 | {:id "client-prod" 32 | :source-paths ["src-cljs/client"] 33 | :compiler {:optimizations :advanced 34 | :output-to "public/js/app-prod.js" 35 | :pretty-print false}} 36 | 37 | {:id "server" 38 | :source-paths ["src-cljs/server"] 39 | :compiler {:language-in :ecmascript5 40 | :language-out :ecmascript5 41 | :optimizations :simple 42 | :output-to "app.js" 43 | :target :nodejs}}]}) 44 | -------------------------------------------------------------------------------- /00-old/src-cljs/client/com/oakmac/snowflake/client/core.cljs: -------------------------------------------------------------------------------- 1 | (ns com.oakmac.snowflake.client.core 2 | (:require 3 | [cljs.reader :refer [read-string]] 4 | [clojure.set :as set] 5 | [clojure.string :as str] 6 | [com.oakmac.snowflake.client.util :refer [by-id js-log log]] 7 | [goog.string :as gstring] 8 | [rum.core :as rum])) 9 | 10 | 11 | ;;------------------------------------------------------------------------------ 12 | ;; Misc 13 | ;;------------------------------------------------------------------------------ 14 | 15 | (defn- split-classname [c] 16 | (let [v (str/split c "-")] 17 | {:full-classname c 18 | :name (str/join "-" (pop v)) 19 | :hash (str "-" (peek v))})) 20 | 21 | ;;------------------------------------------------------------------------------ 22 | ;; Data 23 | ;;------------------------------------------------------------------------------ 24 | 25 | (def flakes-tab "FLAKES") 26 | (def orphans-tab "ORPHANS") 27 | (def tools-tab "TOOLS") 28 | 29 | (def dummy-class-data 30 | {"container-53f43" 31 | {:flake "container-53f43" 32 | :count 3 33 | :definition {"display" "flex" 34 | "max-width" "400px" 35 | "overflow" "auto"} 36 | :files [{:filename "src-cljs/my_proj/bar.cljs", :count 1} 37 | {:filename "src-cljs/my_proj/biz.cljs", :count 1} 38 | {:filename "src-cljs/my_proj/foo.cljs", :count 1}] 39 | :instances [{:filename "src-cljs/my_proj/bar.cljs" 40 | :lines []}]} 41 | 42 | "label-4a5cc" 43 | {:flake "label-4a5cc" 44 | :count 22 45 | :definition {"color" "#aaa" 46 | "display" "block" 47 | "font-size" "11px" 48 | "font-weight" "600" 49 | "margin" "15px 0" 50 | "text-transform" "uppercase"} 51 | :files 52 | [{:filename "src-cljs/my_proj/bar.cljs", :count 5} 53 | {:filename "src-cljs/my_proj/biz.cljs", :count 2} 54 | {:filename "src-cljs/my_proj/foo.cljs", :count 3} 55 | {:filename "templates/athens.mustache", :count 1} 56 | {:filename "templates/chalcis.mustache", :count 1} 57 | {:filename "templates/chania.mustache", :count 1} 58 | {:filename "templates/heraklion.mustache", :count 1} 59 | {:filename "templates/ioannina.mustache", :count 1} 60 | {:filename "templates/larissa.mustache", :count 1} 61 | {:filename "templates/patras.mustache", :count 1} 62 | {:filename "templates/rhodes.mustache", :count 1} 63 | {:filename "templates/thessaloniki.mustache", :count 1} 64 | {:filename "templates/volos.mustache", :count 1}]} 65 | 66 | "header-label-f23ea" 67 | {:flake "header-label-f23ea" 68 | :count 6 69 | :definition {"color" "#999" 70 | "font-size" "14px" 71 | "font-weight" "600" 72 | "text-transform" "uppercase"} 73 | :files [{:filename "src-cljs/my_proj/bar.cljs", :count 2} 74 | {:filename "src-cljs/my_proj/biz.cljs", :count 2} 75 | {:filename "src-cljs/my_proj/foo.cljs", :count 2}]} 76 | 77 | "list-label-27ddb" 78 | {:flake "list-label-27ddb" 79 | :count 8 80 | :definition {"font-family" "\"Open Sans Light\"" 81 | "font-weight" "300" 82 | "font-size" "34px" 83 | "border" "2px solid orange" 84 | "padding" "10px 20px"} 85 | :files [{:filename "templates/larissa.mustache", :count 8}]} 86 | 87 | "clr-7f0e5" 88 | {:flake "clr-7f0e5" 89 | :count 41 90 | :definition {"clear" "both"} 91 | :files 92 | [{:filename "src-cljs/my_proj/biz.cljs", :count 41}]}}) 93 | 94 | (def dummy-single-class (get dummy-class-data "clr-7f0e5")) 95 | 96 | (def dummy-files-list 97 | ["src-cljs/my_proj/bar.cljs" 98 | "src-cljs/my_proj/biz.cljs" 99 | "src-cljs/my_proj/foo.cljs" 100 | "templates/athens.mustache" 101 | "templates/chalcis.mustache" 102 | "templates/chania.mustache" 103 | "templates/heraklion.mustache" 104 | "templates/ioannina.mustache" 105 | "templates/larissa.mustache" 106 | "templates/patras.mustache" 107 | "templates/rhodes.mustache" 108 | "templates/thessaloniki.mustache" 109 | "templates/volos.mustache"]) 110 | 111 | (def all-classes (atom dummy-class-data)) 112 | 113 | (defn- alpha-sort [a b] 114 | (compare (:flake a) (:flake b))) 115 | 116 | (defn- add-classname [[classname c]] 117 | (assoc c :flake classname)) 118 | 119 | (defn- all-classes-sorted-by-name [] 120 | (->> @all-classes 121 | (map add-classname) 122 | (sort alpha-sort) 123 | (into []))) 124 | 125 | (def server-state 126 | "Map of projects and flakes. Is continuously updated from the server." 127 | (atom {})) 128 | 129 | ;;------------------------------------------------------------------------------ 130 | ;; App State 131 | ;;------------------------------------------------------------------------------ 132 | 133 | (def initial-app-state 134 | {:active-project nil 135 | :active-tab flakes-tab 136 | :flakes nil 137 | :flakes-search-txt "" 138 | :projects nil 139 | :socket-connected? false 140 | :sort-flakes-by "a-z" 141 | :selected-flake dummy-single-class}) 142 | 143 | (def app-state (atom initial-app-state)) 144 | 145 | ;;------------------------------------------------------------------------------ 146 | ;; Events 147 | ;;------------------------------------------------------------------------------ 148 | 149 | (defn- on-change-input [js-evt] 150 | (let [new-text (aget js-evt "currentTarget" "value")] 151 | (swap! app-state assoc :search-text new-text))) 152 | 153 | (defn- mark-active [active-idx idx itm] 154 | (if (= active-idx idx) 155 | (assoc itm :active? true) 156 | itm)) 157 | 158 | (defn- on-mouse-enter-class-row [js-evt] 159 | (let [target-el (aget js-evt "currentTarget") 160 | active-idx (int (.getAttribute target-el "data-idx")) 161 | classname (.getAttribute target-el "data-classname") 162 | current-class-list (:classes @app-state) 163 | class-list-with-no-active (map #(dissoc % :active?) current-class-list) 164 | new-class-list (map-indexed (partial mark-active active-idx) class-list-with-no-active)] 165 | ;; defensive - make sure the class exists 166 | (when (get @all-classes classname false) 167 | (swap! app-state assoc :classes (into [] new-class-list) 168 | :files (get-in @all-classes [classname :files]) 169 | :selected-classname classname)))) 170 | 171 | ;;------------------------------------------------------------------------------ 172 | ;; Components 173 | ;;------------------------------------------------------------------------------ 174 | 175 | (rum/defc FileView < rum/static 176 | [] 177 | [:div.fileview-col-c79be "*shows how the classname is used in the file*"]) 178 | 179 | (rum/defc FileRow < rum/static 180 | [f] 181 | [:div.file-row-c9a43 (:filename f)]) 182 | 183 | (rum/defc FilesList < rum/static 184 | [[selected-classname files]] 185 | [:div.files-col-74a77 186 | [:h4.col-title-2c774 "Files" 187 | [:div.count-13cac (str (count files) " files contain " selected-classname)]] 188 | ;; (str "Files that contain: " selected-classname) 189 | [:div.list-wrapper-7462e 190 | (map FileRow files)]]) 191 | 192 | (rum/defc MainInput < rum/static 193 | [search-text] 194 | [:input.main-input-f14b8 195 | {:on-change on-change-input 196 | :placeholder "Search classes and files" 197 | :type "text" 198 | :value search-text}]) 199 | 200 | (defn- change-class-search [js-evt] 201 | (let [new-text (aget js-evt "currentTarget" "value")] 202 | (swap! app-state assoc :flakes-search-txt new-text))) 203 | 204 | (defn- on-change-classes-sort-by [js-evt] 205 | (let [new-value (aget js-evt "currentTarget" "value")] 206 | (swap! app-state assoc :sort-flakes-by new-value))) 207 | 208 | (defn- click-new-class-btn [] 209 | (swap! app-state assoc :new-class-modal-showing? true)) 210 | 211 | (rum/defc UtilBody < rum/static 212 | [] 213 | [:div "TODO: Util Body"]) 214 | 215 | (rum/defc FilesBody < rum/static 216 | [] 217 | [:div "TODO: Files Body"]) 218 | 219 | (defn- sort-first [a b] 220 | (compare (first a) (first b))) 221 | 222 | (rum/defc PropertyListItem < rum/static 223 | [[key val]] 224 | [:li.property-s9fe7 225 | [:span.key-s2dab (str key ":")] 226 | [:span.val-s1b79 val]]) 227 | 228 | (rum/defc ClassDefinitionList < rum/static 229 | [d] 230 | (let [v (sort sort-first (into [] d))] 231 | [:ul.definition-list-s7860 232 | (map PropertyListItem v)])) 233 | 234 | ;; TODO: figure out how this should work... 235 | (def default-preview-styles {}) 236 | 237 | (rum/defc ClassPreview < rum/static 238 | [d] 239 | [:div.preview-wrapper-sb56f 240 | [:div {:style (merge d default-preview-styles)} "Lorem ipsum"]]) 241 | 242 | (rum/defc ClassInstance < rum/static 243 | [instance] 244 | [:div "TODO: instance"]) 245 | 246 | (def active-file-idx 2) 247 | 248 | (rum/defc FileRow2 < rum/static 249 | [idx filename] 250 | [:li {:class (str "file-sbc22" (when (= idx active-file-idx) " active-se4ea"))} 251 | filename]) 252 | 253 | (def dummy-text 254 | ["" 255 | "" 256 | ""]) 259 | 260 | ;; NOTE: this component should show a preview of the text where the class was found 261 | ;; in the file. with things greyed out except for the class name 262 | ;; TODO: 263 | ;; - line numbers 264 | ;; - highlight the class name 265 | (rum/defc TextLine < rum/static 266 | [line] 267 | (js/React.createElement "div" (js-obj "dangerouslySetInnerHTML" 268 | (js-obj "__html" (str "
" 269 | (gstring/htmlEscape line) 270 | "
"))))) 271 | 272 | (rum/defc FilesView < rum/static 273 | [] 274 | [:div.flex-container-s6d73 275 | [:div.files-container-s0cbd 276 | [:ul.files-list-sf03b 277 | (map-indexed FileRow2 dummy-files-list)]] 278 | [:div.text-container-sd0e9 279 | (map TextLine dummy-text)]]) 280 | 281 | (rum/defc RightBody < rum/static 282 | [c] 283 | (let [split-classname (split-classname (:flake c))] 284 | [:div.right-204a5 285 | [:h2.class-name-sb0bc 286 | [:span (:name split-classname)] 287 | [:span.muted-sff17 (:hash split-classname)] 288 | [:span.link-s4dda "rename"]] 289 | ;; TODO: make "files" be a dashed underline 290 | [:p (str "Used " (:count c) " times in " (count (:files c)) " ") 291 | [:span {:style {:text-decoration "underline"}} "files"] 292 | ". Found on " [:code "