;;;; pages.lisp -- html generation functions for dnd
(in-package :dnd)
;;; RENDER PROTOCOL
(defgeneric render (view object &key)
(:documentation "Render OBJECT as VIEW. VIEW could be anything, but it is intended to
be a keyword for usin in EQL method specializers."))
(defmacro defrender (view (spec &rest kwargs) &body body)
"A helper macro for defining specializations of render."
(let ((viewvar (gensym)))
`(defmethod render ((,viewvar (eql ,view)) ,spec &key ,@kwargs)
,@body)))
(defrender :list ((data list) (class "listview") (item-class "listitem"))
"A catch all for rendering lists of renderable data items as unordered
lists. CLASS is the lass string for the containing list. ITEM-CLASS is
the class string for the contained list items."
(with-html
(:ol :class class
(dolist (item data)
(:li (render :list-item item :class item-class))))))
(defrender :three-column-layout (data)
"A catch all specialization for rendering data in three columns. You
must specialize :left :milsddle :right on your desired data type."
(with-html
(:div :class "three-column-layout"
(:div :class "left-column" (render :left data))
(:div :class "middle-column" (render :middle data))
(:div :class "right-column" (render :right data)))))
;;; PAGES
(defmacro with-page ((&key title) &body body)
"A helper macro fordefining some standard page boilerplate."
`(with-html-string
(:doctype)
(:html
(:head
(:title ,title))
(:body
,@body))))
(defclass/std doorkeeper ()
((message)))
(defun doorkeeper (&key (message "Come ye player, Wot's yer name?"))
(render :page (make-instance 'doorkeeper :message message )))
(defrender :page ((page doorkeeper))
(with-page (:title "Tavern Door")
(:h1 (message page))
(:form :method "POST" :action "/tavern-door"
(:label :for "NICK" "Wut's yer handle?:")
(:input :name "NICK")
(:button :type "submit" "Announce Thyself"))
(:h2 "Eh? Ye need to announce thyeself?")
(:a :href "/register" "Follow me...")))
(defclass/std goddess-shrine () ())
(defrender :page ((page goddess-shrine))
(with-page (:title "A Sacred Shrine")
(:header
(:h1 "Pray and become a hero..."))
(:form :method "POST" :action "/godess-shrine"
(:label :for "NAME" "Enter the epithet by which the ages shall know thy hero:")
(:input :name "NAME")
(:button :type "submit" "Pray To The Goddess"))))
(defclass/std player-registration () ())
(defrender :page ((page player-registration))
(with-page (:title "Register Player")
(:header
(:h1 "Choose a Nickname Player"))
(:form :method "POST" :action "/register"
(:label :for "NICK" "Choose a nickname. No spaces. Letters, Numbers, and -._")
(:input :name "NICK" :placeholder "superbob")
(:button :type "submit" "Register"))))
(defun register ()
(render :page (make-instance 'player-registration)))
(defclass/std tavern ()
((player alerts)))
(defun tavern (player)
(render :page (make-instance 'tavern :player player)))
(defrender :page ((tavern tavern))
(with-page (:title "A Bustling Tavern")
(render :three-column-layout tavern)))
(defun tavern-text (player)
(with-page (:title "A Bustling Tavern")
(render :page-text (make-instance 'tavern :player player))))
(defrender :page-text ((tavern tavern))
(let ((player (player tavern)))
(with-html
(render :details player)
(:table
(:tr (:td (:h4 "Your Heroes"))
(:td (:h4 "Your Campaigns")))
(:tr (:td (:h4 "Gossip & Gab"))
(:td (:h4 "Comrades in Arms")))))))
(defrender :left ((tavern tavern))
(let ((player (player tavern)))
(with-html
(render :details player)
(:h4 "Your Heroes")
(render :list (player-heroes player)))))
(defrender :middle ((tavern tavern))
(with-html
(:h4 "Your Campaigns ")
(render :list (player-campaigns (player tavern)))))
(defrender :right ((tavern tavern))
(with-html
(:h4 "Gossip & Gab")
(render :list (alerts tavern))
(:h4 "Comrades in Arms")
(render :list (fetch-comrades (player tavern)))))
(defrender :details ((player player))
(with-html
(:div :class "player details"
(:h3 "Welcome " (player-nick player)))))
(defun navbar ()
(with-html
(:nav :class "navbar" :aria-label "Navigation"
(:div :class "logo" :aria-label "DND logo" "DND")
(:ul :class "nav-links" :aria-label "Nav links"
(:li (:a :href "/hero" :aria-label "Hero profile" "🧝"))
(:li (:a :href "/inventory" :aria-label "Inventory" "🎒"))
(:li (:a :href "/quests" :aria-label "Quests" "📜"))
(:li (:a :href "/tavern" :aria-label "Tavern" "🍺"))))))
(defun hall-of-heroes ()
(with-html
(:ul :class "hall-of-heroes"
(dolist (hero (all-heroes))
(:li (hero-name hero)
"the"
(hero-class hero)
(hero-title hero))))))