/ template-utils.lisp
template-utils.lisp
 1  ;;;; template-utils.lisp - CLIP Template Processing Utilities
 2  ;;;; Proper CLIP-based template rendering using keyword arguments
 3  
 4  (in-package :asteroid)
 5  
 6  ;; Template directory configuration
 7  (defparameter *template-directory*
 8    (merge-pathnames "template/" (asdf:system-source-directory :asteroid))
 9    "Base directory for all CLIP templates")
10  
11  ;; Template cache for parsed templates
12  (defvar *template-cache* (make-hash-table :test 'equal)
13    "Cache for parsed template DOMs")
14  
15  (defun template-path (name)
16    "Build full path to template file.
17     NAME can be either:
18     - Simple name: 'front-page' -> 'template/front-page.ctml'
19     - Path with subdirs: 'partial/now-playing' -> 'template/partial/now-playing.ctml'"
20    (merge-pathnames (format nil "~a.ctml" name) *template-directory*))
21  
22  (defun load-template (name)
23    "Load and parse a template by name without caching.
24     Use this for templates that change frequently during development."
25    (plump:parse (alexandria:read-file-into-string (template-path name))))
26  
27  (defun get-template (template-name)
28    "Load and cache a template file.
29     Use this for production - templates are cached after first load."
30    (or (gethash template-name *template-cache*)
31        (let ((parsed (load-template template-name)))
32          (setf (gethash template-name *template-cache*) parsed)
33          parsed)))
34  
35  (defun clear-template-cache ()
36    "Clear the template cache (useful during development)"
37    (clrhash *template-cache*))
38  
39  (defun render-template-with-plist (template-name &rest plist)
40    "Render a template with plist-style arguments - CLIP's standard way
41     
42     CLIP's process-to-string accepts keyword arguments directly and makes them
43     available via (clip:clipboard key-name) in attribute processors.
44     
45     Example:
46     (render-template-with-plist \"admin\"
47                                 :title \"Admin Dashboard\"
48                                 :server-status \"🟢 Running\")"
49    (let ((template (get-template template-name)))
50      ;; CLIP's standard approach: pass keywords directly
51      (apply #'clip:process-to-string template plist)))
52  
53  ;; Custom CLIP attribute processor for text replacement
54  ;; This is the proper CLIP way - define processors for custom attributes
55  (clip:define-attribute-processor data-text (node value)
56    "Process data-text attribute - replaces node text content with clipboard value
57     Usage: <span data-text=\"key-name\">Default Text</span>"
58    (plump:clear node)
59    (plump:make-text-node node (clip:clipboard value)))