diff --git a/qlfile.lock b/qlfile.lock index 946ad68..0d3e9f0 100644 --- a/qlfile.lock +++ b/qlfile.lock @@ -21,7 +21,7 @@ ("ningle-fbr" . (:class qlot/source/git:source-git :initargs (:remote-url "https://github.com/skyizwhite/ningle-fbr.git") - :version "git-3c83e74a84e57f8ee2a9e98c4045d9b3e7a937f5")) + :version "git-19aae06f7ff17f16f008133a3bf234b89ab7de1e")) ("lack-mw" . (:class qlot/source/git:source-git :initargs (:remote-url "https://github.com/skyizwhite/lack-mw.git") diff --git a/src/api/not-found.lisp b/src/api/not-found.lisp new file mode 100644 index 0000000..8268ad5 --- /dev/null +++ b/src/api/not-found.lisp @@ -0,0 +1,9 @@ +(defpackage #:website/api/not-found + (:use #:cl + #:jingle) + (:export #:handle-not-found)) +(in-package #:website/api/not-found) + +(defun handle-not-found () + (set-response-status :not-found) + '(:|message| "Not found")) diff --git a/src/routes/api/revalidate.lisp b/src/api/revalidate.lisp similarity index 88% rename from src/routes/api/revalidate.lisp rename to src/api/revalidate.lisp index 7e3f1a0..b1ac2bf 100644 --- a/src/routes/api/revalidate.lisp +++ b/src/api/revalidate.lisp @@ -1,17 +1,17 @@ -(defpackage #:website/routes/api/revalidate +(defpackage #:website/api/revalidate (:use #:cl #:jingle #:access) (:import-from #:website/lib/env #:microcms-webhook-key) (:import-from #:website/helper - #:get-request-body-plist) + #:request-body-json->plist) (:import-from #:website/lib/cms #:clear-about-cache #:clear-works-cache #:clear-blog-cache) (:export #:handle-post)) -(in-package #:website/routes/api/revalidate) +(in-package #:website/api/revalidate) (defun handle-post (params) (declare (ignore params)) @@ -19,7 +19,7 @@ (microcms-webhook-key)) (set-response-status :unauthorized) (return-from handle-post '(:|message| "Invalid token"))) - (let* ((body (get-request-body-plist)) + (let* ((body (request-body-json->plist)) (api (getf body :|api|)) (id (getf body :|id|)) (old-draft-key (accesses body :|contents| :|old| :|draftKey|)) diff --git a/src/app.lisp b/src/app.lisp index 957ef97..6e85b2e 100644 --- a/src/app.lisp +++ b/src/app.lisp @@ -1,27 +1,71 @@ (defpackage #:website/app (:use #:cl - #:jingle) + #:jingle + #:hsx) + (:import-from #:jonathan + #:to-json) (:import-from #:ningle-fbr #:set-routes) + (:import-from #:lack/middleware/mount + #:*lack-middleware-mount*) (:import-from #:lack-mw #:*trim-trailing-slash*) (:import-from #:clack-errors #:*clack-error-middleware*) + (:import-from #:website/components/metadata + #:~metadata) + (:import-from #:website/components/scripts + #:~scripts) + (:import-from #:website/components/layout + #:~layout) (:import-from #:website/lib/env #:dev-mode-p) - (:import-from #:website/renderer) (:export #:*app*)) (in-package #:website/app) +(defparameter *page-app* (make-app)) +(set-routes *page-app* :system :website :target-dir-path "pages") + +(defmethod jingle:process-response :around ((app (eql *page-app*)) result) + (set-response-header :content-type "text/html; charset=utf-8") + (when (eq (request-method *request*) :get) + (let ((strategy (context :cache))) + (cond ((dev-mode-p) + (set-response-header :cache-control "private, no-store, must-revalidate")) + ((eq strategy :ssr) + (set-response-header :cache-control "public, max-age=0, must-revalidate")) + ((eq strategy :isr) + (set-response-header :cache-control "public, max-age=0, s-maxage=60, stale-while-revalidate=60")) + ((eq strategy :sg) + (set-response-header :cache-control "public, max-age=0, s-maxage=31536000, must-revalidate"))))) + (call-next-method app + (render-to-string + (hsx (html :lang "en" + (head + (~metadata :metadata (context :metadata)) + (~scripts)) + (body + (~layout result))))))) + +(defparameter *api-app* (make-app)) +(set-routes *api-app* :system :website :target-dir-path "api") + +(defmethod jingle:process-response :around ((app (eql *api-app*)) result) + (set-response-header :content-type "application/json; charset=utf-8") + (call-next-method app (to-json result))) + +(defun with-args (middleware &rest args) + (lambda (app) + (apply middleware app args))) + (defparameter *app* - (let ((app (make-app))) - (set-routes app :system :website :target-dir-path "routes") - (install-middleware app (lambda (app) - (funcall *clack-error-middleware* - app - :debug (dev-mode-p)))) - (install-middleware app *trim-trailing-slash*) - (static-path app "/assets/" "assets/") - (configure app))) + (progn + (install-middleware *page-app* + (with-args *lack-middleware-mount* "/api" *api-app*)) + (install-middleware *page-app* + (with-args *clack-error-middleware* :debug (dev-mode-p))) + (install-middleware *page-app* *trim-trailing-slash*) + (static-path *page-app* "/assets/" "assets/") + (configure *page-app*))) *app* diff --git a/src/helper.lisp b/src/helper.lisp index c208395..d2fe236 100644 --- a/src/helper.lisp +++ b/src/helper.lisp @@ -5,18 +5,12 @@ #:make-flexi-stream) (:import-from #:jonathan #:parse) - (:export #:api-request-p - #:get-request-body-plist)) + (:export #:request-body-json->plist + #:set-metadata + #:set-cache)) (in-package #:website/helper) -(defun starts-with-p (prefix string) - (let ((pos (search prefix string :start1 0 :end1 (length prefix) :start2 0))) - (and pos (= pos 0)))) - -(defun api-request-p () - (starts-with-p "/api/" (request-uri *request*))) - -(defun get-request-body-plist () +(defun request-body-json->plist () (parse (let ((text-stream (make-flexi-stream (request-raw-body *request*) :external-format :utf-8))) @@ -24,3 +18,9 @@ (loop :for char := (read-char text-stream nil) :while char :do (write-char char out)))))) + +(defun set-metadata (metadata) + (setf (context :metadata) metadata)) + +(defun set-cache (strategy) + (setf (context :cache) strategy)) diff --git a/src/routes/about.lisp b/src/pages/about.lisp similarity index 74% rename from src/routes/about.lisp rename to src/pages/about.lisp index 99ca377..06dab91 100644 --- a/src/routes/about.lisp +++ b/src/pages/about.lisp @@ -1,21 +1,22 @@ -(defpackage #:website/routes/about +(defpackage #:website/pages/about (:use #:cl #:hsx - #:jingle) + #:jingle + #:website/helper) (:import-from #:website/lib/cms #:fetch-about) (:import-from #:website/components/article #:~article) (:export #:handle-get)) -(in-package #:website/routes/about) +(in-package #:website/pages/about) (defparameter *metadata* (list :title "about")) (defun handle-get (params) - (setf (context :metadata) *metadata*) + (set-metadata *metadata*) (with-request-params ((draft-key "draft-key" nil)) params - (setf (context :cache) (if draft-key :ssr :isr)) + (set-cache (if draft-key :ssr :isr)) (let ((about (fetch-about :draft-key draft-key))) (~article :title "About" diff --git a/src/routes/blog/<id>.lisp b/src/pages/blog/<id>.lisp similarity index 64% rename from src/routes/blog/<id>.lisp rename to src/pages/blog/<id>.lisp index 43d2d2a..2093ea9 100644 --- a/src/routes/blog/<id>.lisp +++ b/src/pages/blog/<id>.lisp @@ -1,15 +1,16 @@ -(defpackage #:website/routes/blog/<id> +(defpackage #:website/pages/blog/<id> (:use #:cl #:hsx - #:jingle) + #:jingle + #:website/helper) (:import-from #:website/lib/cms #:fetch-blog-detail) - (:import-from #:website/routes/not-found + (:import-from #:website/pages/not-found #:handle-not-found) (:import-from #:website/components/article #:~article) (:export #:handle-get)) -(in-package #:website/routes/blog/<id>) +(in-package #:website/pages/blog/<id>) (defun handle-get (params) (with-request-params ((id :id nil) @@ -17,10 +18,10 @@ (let ((blog (fetch-blog-detail id :draft-key draft-key))) (unless blog (return-from handle-get (handle-not-found))) - (setf (context :cache) (if draft-key :ssr :isr)) - (setf (context :metadata) (list :title (getf blog :title) - :description (getf blog :description) - :type "article")) + (set-cache (if draft-key :ssr :isr)) + (set-metadata (list :title (getf blog :title) + :description (getf blog :description) + :type "article")) (hsx (~article :title (getf blog :title) diff --git a/src/routes/blog/index.lisp b/src/pages/blog/index.lisp similarity index 84% rename from src/routes/blog/index.lisp rename to src/pages/blog/index.lisp index ff668c6..8bc73d3 100644 --- a/src/routes/blog/index.lisp +++ b/src/pages/blog/index.lisp @@ -1,21 +1,22 @@ -(defpackage #:website/routes/blog/index +(defpackage #:website/pages/blog/index (:use #:cl #:hsx - #:jingle) + #:jingle + #:website/helper) (:import-from #:website/lib/cms #:fetch-blog-list) (:import-from #:website/lib/time #:asctime) (:export #:handle-get)) -(in-package #:website/routes/blog/index) +(in-package #:website/pages/blog/index) (defparameter *metadata* (list :title "blog")) (defun handle-get (params) (declare (ignore params)) - (setf (context :cache) :isr) - (setf (context :metadata) *metadata*) + (set-cache :isr) + (set-metadata *metadata*) (let ((blogs (fetch-blog-list :page 1))) (hsx (section diff --git a/src/routes/index.lisp b/src/pages/index.lisp similarity index 92% rename from src/routes/index.lisp rename to src/pages/index.lisp index 663a7ae..74c4565 100644 --- a/src/routes/index.lisp +++ b/src/pages/index.lisp @@ -1,13 +1,14 @@ -(defpackage #:website/routes/index +(defpackage #:website/pages/index (:use #:cl #:hsx #:access - #:jingle) + #:jingle + #:website/helper) (:import-from #:website/lib/cms #:get-about) (:export #:handle-get #:handle-head)) -(in-package #:website/routes/index) +(in-package #:website/pages/index) (defparameter *links* '(("Keyoxide" @@ -28,7 +29,7 @@ (defun handle-get (params) (declare (ignore params)) - (setf (context :cache) :sg) + (set-cache :sg) (hsx (div :class "flex flex-col items-center justify-center h-full" (img diff --git a/src/pages/not-found.lisp b/src/pages/not-found.lisp new file mode 100644 index 0000000..80e7e2e --- /dev/null +++ b/src/pages/not-found.lisp @@ -0,0 +1,23 @@ +(defpackage #:website/pages/not-found + (:use #:cl + #:hsx + #:jingle + #:website/helper) + (:export #:handle-not-found)) +(in-package #:website/pages/not-found) + +(defparameter *metadata* + '(:title "404 Not Found" + :description "The page you are looking for may have been deleted or the URL might be incorrect." + :error t)) + +(defun handle-not-found () + (set-response-status :not-found) + (set-cache :ssr) + (set-metadata *metadata*) + (hsx + (div :class "flex flex-col h-full items-center justify-center gap-y-6" + (h1 :class "font-bold text-2xl" + "404 Not Found") + (a :href "/" :class "text-lg text-pink-500 hover:underline" + "Back to TOP")))) diff --git a/src/routes/works.lisp b/src/pages/works.lisp similarity index 74% rename from src/routes/works.lisp rename to src/pages/works.lisp index 68da918..6f8f75e 100644 --- a/src/routes/works.lisp +++ b/src/pages/works.lisp @@ -1,21 +1,22 @@ -(defpackage #:website/routes/works +(defpackage #:website/pages/works (:use #:cl #:hsx - #:jingle) + #:jingle + #:website/helper) (:import-from #:website/lib/cms #:fetch-works) (:import-from #:website/components/article #:~article) (:export #:handle-get)) -(in-package #:website/routes/works) +(in-package #:website/pages/works) (defparameter *metadata* (list :title "works")) (defun handle-get (params) - (setf (context :metadata) *metadata*) + (set-metadata *metadata*) (with-request-params ((draft-key "draft-key" nil)) params - (setf (context :cache) (if draft-key :ssr :isr)) + (set-cache (if draft-key :ssr :isr)) (let ((works (fetch-works :draft-key draft-key))) (~article :title "Works" diff --git a/src/renderer.lisp b/src/renderer.lisp deleted file mode 100644 index 61bb55a..0000000 --- a/src/renderer.lisp +++ /dev/null @@ -1,42 +0,0 @@ -(defpackage #:website/renderer - (:use #:cl - #:hsx - #:jingle) - (:import-from #:jonathan - #:to-json) - (:import-from #:website/lib/env - #:dev-mode-p) - (:import-from #:website/helper - #:api-request-p) - (:import-from #:website/components/metadata - #:~metadata) - (:import-from #:website/components/scripts - #:~scripts) - (:import-from #:website/components/layout - #:~layout)) -(in-package #:website/renderer) - -(defmethod jingle:process-response :around ((app jingle:app) result) - (when (eq (request-method *request*) :get) - (let ((strategy (context :cache))) - (cond ((dev-mode-p) - (set-response-header :cache-control "private, no-store, must-revalidate")) - ((eq strategy :ssr) - (set-response-header :cache-control "public, max-age=0, must-revalidate")) - ((eq strategy :isr) - (set-response-header :cache-control "public, max-age=0, s-maxage=60, stale-while-revalidate=60")) - ((eq strategy :sg) - (set-response-header :cache-control "public, max-age=0, s-maxage=31536000, must-revalidate"))))) - (cond ((api-request-p) - (set-response-header :content-type "application/json; charset=utf-8") - (call-next-method app (to-json result))) - (t - (set-response-header :content-type "text/html; charset=utf-8") - (call-next-method app - (render-to-string - (hsx (html :lang "en" - (head - (~metadata :metadata (context :metadata)) - (~scripts)) - (body - (~layout result))))))))) diff --git a/src/routes/not-found.lisp b/src/routes/not-found.lisp deleted file mode 100644 index dc6a623..0000000 --- a/src/routes/not-found.lisp +++ /dev/null @@ -1,26 +0,0 @@ -(defpackage #:website/routes/not-found - (:use #:cl - #:hsx - #:jingle) - (:import-from #:website/helper - #:api-request-p) - (:export #:handle-not-found)) -(in-package #:website/routes/not-found) - -(defparameter *metadata* - '(:title "404 Not Found" - :description "The page you are looking for may have been deleted or the URL might be incorrect." - :error t)) - -(defun handle-not-found () - (set-response-status :not-found) - (setf (context :cache) :ssr) - (setf (context :metadata) *metadata*) - (if (api-request-p) - '(:|message| "404 Not Found") - (hsx - (div :class "flex flex-col h-full items-center justify-center gap-y-6" - (h1 :class "font-bold text-2xl" - "404 Not Found") - (a :href "/" :class "text-lg text-pink-500 hover:underline" - "Back to TOP"))))) diff --git a/tailwind.config.js b/tailwind.config.js index 738e1dd..31d339b 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,8 +1,7 @@ /** @type {import('tailwindcss').Config} */ module.exports = { content: [ - "./src/renderer.lisp", - "./src/routes/**/*.lisp", + "./src/pages/**/*.lisp", "./src/components/**/*.lisp", ], theme: {