HTMX + Alpine.js + TailwindCSS
This commit is contained in:
parent
b62a2dd8c4
commit
d614f039d3
37 changed files with 114 additions and 233 deletions
.gitignoreMakefileREADME.md
assets
css
img
js/pages
vendor
public
src
tailwind.config.js
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
.qlot
|
||||
.qlot
|
||||
public/dist.css
|
||||
|
|
15
Makefile
Normal file
15
Makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
install: ## Install dependencies
|
||||
@qlot install
|
||||
|
||||
dev: ## Run dev mode
|
||||
@tailwindcss -i ./public/global.css -o ./public/dist.css --watch=always < /dev/null &
|
||||
|
||||
stop: ## Stop dev mode
|
||||
@pkill -f tailwind
|
||||
|
||||
build: ## Build
|
||||
@tailwindcss -i ./public/global.css -o ./public/dist.css
|
||||
|
||||
help: ## Show options
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
||||
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
|
@ -1,3 +1 @@
|
|||
# homepage (WIP)
|
||||
|
||||
My homepage made with Common Lisp, HTMX and Alpine.js.
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
@scope ([data-css='components/layout/footer.css']) {
|
||||
:scope {
|
||||
height: 40px;
|
||||
background-color: gray;
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
@scope ([data-css='components/layout/header.css']) {
|
||||
:scope {
|
||||
height: 80px;
|
||||
display: flex;
|
||||
background-color: gray;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
@scope ([data-css='components/layout/main.css']) {
|
||||
:scope {
|
||||
height: 100svh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
@scope ([data-css='pages/index.css']) {
|
||||
:scope {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
}
|
||||
}
|
Binary file not shown.
Before ![]() (image error) Size: 211 KiB |
File diff suppressed because one or more lines are too long
1
assets/vendor/ress@5.0.2.css
vendored
1
assets/vendor/ress@5.0.2.css
vendored
|
@ -1 +0,0 @@
|
|||
html{-webkit-text-size-adjust:100%;box-sizing:border-box;-moz-tab-size:4;tab-size:4;word-break:normal}*,:after,:before{background-repeat:no-repeat;box-sizing:inherit}:after,:before{text-decoration:inherit;vertical-align:inherit}*{margin:0;padding:0}hr{color:inherit;height:0;overflow:visible}details,main{display:block}summary{display:list-item}small{font-size:80%}[hidden]{display:none}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}a{background-color:transparent}a:active,a:hover{outline-width:0}code,kbd,pre,samp{font-family:monospace,monospace}pre{font-size:1em}b,strong{font-weight:bolder}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-color:inherit;text-indent:0}iframe{border-style:none}input{border-radius:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}textarea{overflow:auto;resize:vertical}button,input,optgroup,select,textarea{font:inherit}optgroup{font-weight:700}button{overflow:visible}button,select{text-transform:none}[role=button],[type=button],[type=reset],[type=submit],button{cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button:-moz-focusring{outline:1px dotted ButtonText}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}button,input,select,textarea{background-color:transparent;border-style:none}a:focus,button:focus,input:focus,select:focus,textarea:focus{outline-width:0}select{-moz-appearance:none;-webkit-appearance:none}select::-ms-expand{display:none}select::-ms-value{color:currentColor}legend{border:0;color:inherit;display:table;max-width:100%;white-space:normal}::-webkit-file-upload-button{-webkit-appearance:button;color:inherit;font:inherit}[disabled]{cursor:default}img{border-style:none}progress{vertical-align:baseline}[aria-busy=true]{cursor:progress}[aria-controls]{cursor:pointer}[aria-disabled=true]{cursor:default}
|
|
@ -1,8 +1,8 @@
|
|||
@charset "utf-8";
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
html {
|
||||
font-family: "Noto Sans JP", sans-serif;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
|
@ -14,9 +14,13 @@
|
|||
:port cfg:*port*))
|
||||
|
||||
(defun start ()
|
||||
(if (cfg:dev-mode-p)
|
||||
(uiop:run-program "make dev"))
|
||||
(jg:start *app*))
|
||||
|
||||
(defun stop ()
|
||||
(if (cfg:dev-mode-p)
|
||||
(uiop:run-program "make stop"))
|
||||
(jg:stop *app*))
|
||||
|
||||
(defun setup ()
|
||||
|
@ -24,9 +28,8 @@
|
|||
(jg:clear-routing-rules *app*)
|
||||
(fbr:assign-routes *app* :system "hp" :directory "src/routes")
|
||||
(jg:install-middleware *app* mw:*path-normalizer*)
|
||||
(jg:install-middleware *app* mw:*assets-server*)
|
||||
(jg:install-middleware *app* mw:*public-server*)
|
||||
(jg:install-middleware *app* mw:*access-logger*)
|
||||
(jg:install-middleware *app* mw:*access-blocker*)
|
||||
(jg:install-middleware *app* mw:*recoverer*))
|
||||
|
||||
(defun update ()
|
||||
|
|
43
src/components/document.lisp
Normal file
43
src/components/document.lisp
Normal file
|
@ -0,0 +1,43 @@
|
|||
(defpackage #:hp/components/document
|
||||
(:use #:cl)
|
||||
(:local-nicknames (#:pi #:piccolo))
|
||||
(:import-from #:hp/view/asset
|
||||
#:defasset)
|
||||
(:export #:document))
|
||||
(in-package #:hp/components/document)
|
||||
|
||||
(defasset *htmx* :vendor "htmx@1.9.12.js")
|
||||
(defasset *htmx-exts* :htmx-ext
|
||||
("alpine-morph@1.9.12.js"
|
||||
"head-support@1.9.12.js"))
|
||||
|
||||
(defasset *alpine* :vendor "alpine@3.13.8.js")
|
||||
(defasset *alpine-exts* :alpine-ext
|
||||
("morph@3.13.8.js"
|
||||
"persist@3.13.8.js"))
|
||||
(defasset *alpine-store* :root "store.js")
|
||||
|
||||
(defasset *global-css* :root "global.css")
|
||||
(defasset *dist-css* :root "dist.css")
|
||||
|
||||
(pi:define-element document (title description)
|
||||
(pi:h
|
||||
(html :lang "ja"
|
||||
(head
|
||||
(meta :charset "UTF-8")
|
||||
(script :src *htmx*)
|
||||
(mapcar (lambda (path) (script :src path))
|
||||
*htmx-exts*)
|
||||
(mapcar (lambda (path) (script :src path :defer t))
|
||||
*alpine-exts*)
|
||||
(script :src *alpine-store* :defer t)
|
||||
(script :src *alpine* :defer t)
|
||||
(style
|
||||
"@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');")
|
||||
(link :rel "stylesheet" :type "text/css" :href *global-css*)
|
||||
(link :rel "stylesheet" :type "text/css" :href *dist-css*)
|
||||
(title (format nil "~@[~a - ~]skyizwhite.dev" title))
|
||||
(meta
|
||||
:name "description"
|
||||
:content (or description "pakuの個人サイト")))
|
||||
pi:children)))
|
|
@ -1,30 +0,0 @@
|
|||
(defpackage #:hp/components/document/main
|
||||
(:use #:cl)
|
||||
(:local-nicknames (#:pi #:piccolo))
|
||||
(:import-from #:hp/components/document/styles
|
||||
#:styles
|
||||
#:on-demand-styles)
|
||||
(:import-from #:hp/components/document/scripts
|
||||
#:scripts)
|
||||
(:import-from #:hp/components/document/seo
|
||||
#:seo)
|
||||
(:export #:document
|
||||
#:partial-document))
|
||||
(in-package #:hp/components/document/main)
|
||||
|
||||
(pi:define-element document (metadata)
|
||||
(pi:h
|
||||
(html :lang "ja"
|
||||
(head
|
||||
(meta :charset "UTF-8")
|
||||
(styles pi:children)
|
||||
(scripts)
|
||||
(seo metadata))
|
||||
pi:children)))
|
||||
|
||||
(pi:define-element partial-document ()
|
||||
(pi:h
|
||||
(<>
|
||||
(head :hx-head "append"
|
||||
(on-demand-styles pi:children))
|
||||
pi:children)))
|
|
@ -1,36 +0,0 @@
|
|||
(defpackage #:hp/components/document/scripts
|
||||
(:use #:cl)
|
||||
(:local-nicknames (#:pi #:piccolo))
|
||||
(:import-from #:hp/view/asset
|
||||
#:defasset)
|
||||
(:export #:scripts))
|
||||
(in-package #:hp/components/document/scripts)
|
||||
|
||||
(defasset *htmx* :vendor "htmx@1.9.12.js")
|
||||
(defasset *htmx-exts* :htmx-ext
|
||||
("alpine-morph@1.9.12.js"
|
||||
"head-support@1.9.12.js"))
|
||||
|
||||
(defasset *alpine* :vendor "alpine@3.13.8.js")
|
||||
(defasset *alpine-exts* :alpine-ext
|
||||
("async-alpine@1.2.2.js"
|
||||
"persist@3.13.8.js"
|
||||
"morph@3.13.8.js"))
|
||||
|
||||
(defasset *global* :js "global.js")
|
||||
|
||||
(pi:define-element extentions (paths defer)
|
||||
(pi:h
|
||||
(<>
|
||||
(mapcar (lambda (path)
|
||||
(script :src path :defer defer))
|
||||
paths))))
|
||||
|
||||
(pi:define-element scripts ()
|
||||
(pi:h
|
||||
(<>
|
||||
(script :src *htmx*)
|
||||
(extentions :paths *htmx-exts*)
|
||||
(extentions :paths *alpine-exts* :defer t)
|
||||
(script :src *global* :defer t)
|
||||
(script :src *alpine* :defer t))))
|
|
@ -1,13 +0,0 @@
|
|||
(defpackage #:hp/components/document/seo
|
||||
(:use #:cl)
|
||||
(:local-nicknames (#:pi #:piccolo))
|
||||
(:export #:seo))
|
||||
(in-package #:hp/components/document/seo)
|
||||
|
||||
(pi:define-element seo (title description)
|
||||
(pi:h
|
||||
(<>
|
||||
(title (format nil "~@[~a - ~]skyizwhite.dev" title))
|
||||
(meta
|
||||
:name "description"
|
||||
:content (or description "pakuの個人サイト")))))
|
|
@ -1,34 +0,0 @@
|
|||
(defpackage #:hp/components/document/styles
|
||||
(:use #:cl)
|
||||
(:local-nicknames (#:pi #:piccolo))
|
||||
(:import-from #:hp/view/asset
|
||||
#:defasset
|
||||
#:get-css-paths)
|
||||
(:export #:on-demand-styles
|
||||
#:styles))
|
||||
(in-package #:hp/components/document/styles)
|
||||
|
||||
(defasset *ress* :vendor "ress@5.0.2.css")
|
||||
(defasset *global* :css "global.css")
|
||||
|
||||
(pi:define-element on-demand-styles ()
|
||||
(let* ((html-str (let ((pi:*escape-html* nil))
|
||||
(pi:elem-str pi:children)))
|
||||
(css-paths (get-css-paths html-str)))
|
||||
(pi:h
|
||||
(<>
|
||||
(mapcar (lambda (path)
|
||||
(link :rel "stylesheet" :type "text/css" :href path))
|
||||
css-paths)))))
|
||||
|
||||
(pi:define-element styles ()
|
||||
(pi:h
|
||||
(<>
|
||||
(link :rel "stylesheet" :type "text/css" :href *ress*)
|
||||
(link :rel "stylesheet" :type "text/css" :href *global*)
|
||||
(on-demand-styles pi:children)
|
||||
(link :rel "preconnect" :href "https://fonts.googleapis.com")
|
||||
(link :rel "preconnect" :href "https://fonts.gstatic.com" :crossorigin t)
|
||||
(link
|
||||
:rel "stylesheet"
|
||||
:href "https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap"))))
|
17
src/components/layout.lisp
Normal file
17
src/components/layout.lisp
Normal file
|
@ -0,0 +1,17 @@
|
|||
(defpackage #:hp/components/layout
|
||||
(:use #:cl)
|
||||
(:local-nicknames (#:pi #:piccolo))
|
||||
(:local-nicknames (#:cfg #:hp/config/*))
|
||||
(:export #:layout))
|
||||
(in-package #:hp/components/layout)
|
||||
|
||||
(pi:define-element layout ()
|
||||
(pi:h
|
||||
(body
|
||||
:hx-ext cfg:*hx-ext*
|
||||
:class "h-[100svh] flex flex-col"
|
||||
(header)
|
||||
(main :class "flex-1"
|
||||
pi:children)
|
||||
; footer
|
||||
(footer))))
|
|
@ -1,9 +0,0 @@
|
|||
(defpackage #:hp/components/layout/footer
|
||||
(:use #:cl)
|
||||
(:local-nicknames (#:pi #:piccolo))
|
||||
(:export #:layout-footer))
|
||||
(in-package #:hp/components/layout/footer)
|
||||
|
||||
(pi:define-element layout-footer ()
|
||||
(pi:h
|
||||
(footer :data-css "components/layout/footer.css")))
|
|
@ -1,10 +0,0 @@
|
|||
(defpackage #:hp/components/layout/header
|
||||
(:use #:cl)
|
||||
(:local-nicknames (#:pi #:piccolo))
|
||||
(:export #:layout-header))
|
||||
(in-package #:hp/components/layout/header)
|
||||
|
||||
(pi:define-element layout-header ()
|
||||
(pi:h
|
||||
(header :data-css "components/layout/header.css"
|
||||
(p "skyizwhite.dev"))))
|
|
@ -1,21 +0,0 @@
|
|||
(defpackage #:hp/components/layout/main
|
||||
(:use #:cl)
|
||||
(:local-nicknames (#:pi #:piccolo))
|
||||
(:local-nicknames (#:cfg #:hp/config/asset))
|
||||
(:import-from #:hp/components/layout/header
|
||||
#:layout-header)
|
||||
(:import-from #:hp/components/layout/footer
|
||||
#:layout-footer)
|
||||
(:export #:layout))
|
||||
(in-package #:hp/components/layout/main)
|
||||
|
||||
(pi:define-element layout ()
|
||||
(pi:h
|
||||
(body
|
||||
:hx-ext cfg:*hx-ext*
|
||||
:data-css "components/layout/main.css"
|
||||
(layout-header)
|
||||
(main :class "main"
|
||||
pi:children)
|
||||
(layout-footer)
|
||||
)))
|
|
@ -5,9 +5,8 @@
|
|||
(in-package #:hp/config/asset)
|
||||
|
||||
(defparameter *asset-roots*
|
||||
'(:img "/img/"
|
||||
:css "/css/"
|
||||
:js "/js/"
|
||||
'(:root "/"
|
||||
:img "/img/"
|
||||
:vendor "/vendor/"
|
||||
:htmx-ext "/vendor/htmx-ext/"
|
||||
:alpine-ext "/vendor/alpine-ext/"))
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
(defpackage #:hp/middlewares/access-blocker
|
||||
(:use #:cl)
|
||||
(:local-nicknames (#:re #:cl-ppcre))
|
||||
(:export #:*access-blocker*))
|
||||
(in-package #:hp/middlewares/access-blocker)
|
||||
|
||||
(defparameter *access-blocker*
|
||||
(lambda (app)
|
||||
(lambda (env)
|
||||
(let ((user-agent (gethash "user-agent" (getf env :headers))))
|
||||
(if (re:scan "(Firefox|SamsungBrowser)" user-agent)
|
||||
`(:400
|
||||
(:content-type "text/plain")
|
||||
("This site is not compatible with your browser. Please use Chrome, Edge, Safari, or another compatible browser."))
|
||||
(funcall app env))))))
|
|
@ -1,18 +1,18 @@
|
|||
(defpackage #:hp/middlewares/assets-server
|
||||
(defpackage #:hp/middlewares/public-server
|
||||
(:use #:cl)
|
||||
(:import-from #:lack.middleware.static
|
||||
#:*lack-middleware-static*)
|
||||
(:export #:*assets-server*))
|
||||
(in-package #:hp/middlewares/assets-server)
|
||||
(:export #:*public-server*))
|
||||
(in-package #:hp/middlewares/public-server)
|
||||
|
||||
(defun exist-asset-file-p (path)
|
||||
(let ((pathname (probe-file (concatenate 'string "assets" path))))
|
||||
(let ((pathname (probe-file (concatenate 'string "public" path))))
|
||||
(and pathname (pathname-name pathname))))
|
||||
|
||||
(defparameter *assets-server*
|
||||
(defparameter *public-server*
|
||||
(lambda (app)
|
||||
(funcall *lack-middleware-static*
|
||||
app
|
||||
:path (lambda (path)
|
||||
(and (exist-asset-file-p path) path))
|
||||
:root (asdf:system-relative-pathname :hp "assets/"))))
|
||||
:root (asdf:system-relative-pathname :hp "public/"))))
|
|
@ -7,8 +7,13 @@
|
|||
|
||||
(pi:define-element page ()
|
||||
(pi:h
|
||||
(div :data-css "pages/index.css"
|
||||
(h1 "Hello, World!"))))
|
||||
(div :class "h-full place-content-center"
|
||||
(h1
|
||||
:x-data "{flag: true}"
|
||||
:@click "flag = ! flag"
|
||||
:class "text-4xl text-center"
|
||||
:|:class| "flag ? 'text-red-400' : 'text-blue-400'"
|
||||
"Hello, world!"))))
|
||||
|
||||
(defun handle-get (params)
|
||||
(declare (ignore params))
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
(:local-nicknames (#:re #:cl-ppcre))
|
||||
(:local-nicknames (#:cfg #:hp/config/asset))
|
||||
(:export #:asset-root
|
||||
#:defasset
|
||||
#:get-css-paths))
|
||||
#:defasset))
|
||||
(in-package #:hp/view/asset)
|
||||
|
||||
(defun asset-root (kind)
|
||||
|
@ -21,12 +20,3 @@
|
|||
`(defparameter ,name
|
||||
(,(if (listp files) 'mapcar 'funcall)
|
||||
(asset-path-under ,kind) ',files)))
|
||||
|
||||
(defun detect-attr-vals (html attr)
|
||||
(let* ((regex (format nil "(?<=~a=\")[^\"]*(?=\")" attr))
|
||||
(vals (re:all-matches-as-strings regex html)))
|
||||
(remove-duplicates vals :test #'string=)))
|
||||
|
||||
(defun get-css-paths (html)
|
||||
(mapcar (asset-path-under :css)
|
||||
(detect-attr-vals html "data-css")))
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
(:local-nicknames (#:jg #:jingle))
|
||||
(:local-nicknames (#:pi #:piccolo))
|
||||
(:local-nicknames (#:cfg #:hp/config/env))
|
||||
(:local-nicknames (#:cmp #:hp/components/**/*))
|
||||
(:local-nicknames (#:cmp #:hp/components/*))
|
||||
(:export #:render
|
||||
#:partial-render))
|
||||
(in-package #:hp/view/renderer)
|
||||
|
@ -22,4 +22,4 @@
|
|||
(defun partial-render (component &key status)
|
||||
(jg:with-html-response
|
||||
(if status (jg:set-response-status status))
|
||||
(funcall (renderer) (cmp:partial-document component))))
|
||||
(funcall (renderer) component)))
|
||||
|
|
11
tailwind.config.js
Normal file
11
tailwind.config.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./src/routes/**/*.lisp",
|
||||
"./src/components/**/*.lisp"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue