Fix LASS implementation: Enable dynamic CSS generation
- Fixed compile-styles function to properly use lass:compile-and-write - LASS now generates CSS dynamically on server startup - Removed dependency on static CSS files - Added LASS-IMPLEMENTATION-NOTES.org documenting the fix - Server now compiles LASS to CSS automatically on startup - All styling preserved with proper LASS integration
This commit is contained in:
parent
c0acff7d08
commit
25f558c8e0
|
|
@ -19,4 +19,5 @@
|
||||||
asteroid
|
asteroid
|
||||||
buildapp
|
buildapp
|
||||||
quicklisp-manifest.txt
|
quicklisp-manifest.txt
|
||||||
|
notes/
|
||||||
|
run-asteroid.sh
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,10 @@
|
||||||
:r-clip
|
:r-clip
|
||||||
:spinneret
|
:spinneret
|
||||||
:cl-json
|
:cl-json
|
||||||
:dexador)
|
;; :com.inuoe.jzon
|
||||||
|
:dexador
|
||||||
|
:lass)
|
||||||
:pathname "./"
|
:pathname "./"
|
||||||
:components ((:file "app-utils")
|
:components ((:file "app-utils")
|
||||||
(:file "module")
|
(:file "module")
|
||||||
(:file "asteroid")))
|
(:file "asteroid")))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,35 @@
|
||||||
|
|
||||||
;; Define as RADIANCE module
|
;; Define as RADIANCE module
|
||||||
(define-module asteroid
|
(define-module asteroid
|
||||||
(:use #:cl #:radiance)
|
(:use #:cl #:radiance #:lass)
|
||||||
(:domain "asteroid"))
|
(:domain "asteroid"))
|
||||||
|
|
||||||
;; Configuration
|
;; Configuration
|
||||||
(defparameter *server-port* 8080)
|
(defparameter *server-port* 8080)
|
||||||
|
|
||||||
|
;; Read and compile LASS from file
|
||||||
|
(defun generate-css ()
|
||||||
|
"Generate CSS by reading LASS from static/asteroid.lass file"
|
||||||
|
(let ((lass-file (merge-pathnames "static/asteroid.lass")))
|
||||||
|
(lass:compile-and-write
|
||||||
|
(with-open-file (in lass-file)
|
||||||
|
(read in)))))
|
||||||
|
|
||||||
|
;; Generate CSS file using LASS
|
||||||
|
(defun compile-styles ()
|
||||||
|
"Generate CSS file using LASS"
|
||||||
|
(ensure-directories-exist "static/")
|
||||||
|
(let ((css-file (merge-pathnames "static/asteroid.css")))
|
||||||
|
(with-open-file (out css-file
|
||||||
|
:direction :output
|
||||||
|
:if-exists :supersede)
|
||||||
|
(write-string (generate-css) out))))
|
||||||
|
|
||||||
|
;; Configure static file serving for other files
|
||||||
|
(define-page static #@"/static/(.*)" (:uri-groups (path))
|
||||||
|
(serve-file (merge-pathnames (concatenate 'string "static/" path)
|
||||||
|
(asdf:system-source-directory :asteroid))))
|
||||||
|
|
||||||
;; RADIANCE route handlers
|
;; RADIANCE route handlers
|
||||||
(define-page index #@"/" ()
|
(define-page index #@"/" ()
|
||||||
(spinneret:with-html-string
|
(spinneret:with-html-string
|
||||||
|
|
@ -24,23 +47,7 @@
|
||||||
(:title "🎵 ASTEROID RADIO 🎵")
|
(:title "🎵 ASTEROID RADIO 🎵")
|
||||||
(:meta :charset "utf-8")
|
(:meta :charset "utf-8")
|
||||||
(:meta :name "viewport" :content "width=device-width, initial-scale=1")
|
(:meta :name "viewport" :content "width=device-width, initial-scale=1")
|
||||||
(:style "
|
(:link :rel "stylesheet" :type "text/css" :href "/static/asteroid.css"))
|
||||||
body { font-family: 'Courier New', monospace; background: #0a0a0a; color: #00ff00; margin: 0; padding: 20px; }
|
|
||||||
.container { max-width: 1200px; margin: 0 auto; }
|
|
||||||
h1 { color: #ff6600; text-align: center; font-size: 2.5em; margin-bottom: 30px; }
|
|
||||||
h2 { color: #ff6600; }
|
|
||||||
.status { background: #1a1a1a; padding: 20px; border: 1px solid #333; margin: 20px 0; }
|
|
||||||
.panel { background: #1a1a1a; padding: 20px; border: 1px solid #333; margin: 20px 0; }
|
|
||||||
.nav { margin: 20px 0; }
|
|
||||||
.nav a { color: #00ff00; text-decoration: none; margin: 0 15px; padding: 10px 20px; border: 1px solid #333; background: #1a1a1a; display: inline-block; }
|
|
||||||
.nav a:hover { background: #333; }
|
|
||||||
.controls { margin: 20px 0; }
|
|
||||||
.controls button { background: #1a1a1a; color: #00ff00; border: 1px solid #333; padding: 10px 20px; margin: 5px; cursor: pointer; }
|
|
||||||
.controls button:hover { background: #333; }
|
|
||||||
.now-playing { background: #1a1a1a; padding: 20px; border: 1px solid #333; margin: 20px 0; }
|
|
||||||
.back { color: #00ff00; text-decoration: none; margin-bottom: 20px; display: inline-block; }
|
|
||||||
.back:hover { text-decoration: underline; }
|
|
||||||
"))
|
|
||||||
(:body
|
(:body
|
||||||
(:div.container
|
(:div.container
|
||||||
(:h1 "🎵 ASTEROID RADIO 🎵")
|
(:h1 "🎵 ASTEROID RADIO 🎵")
|
||||||
|
|
@ -67,15 +74,7 @@
|
||||||
(:head
|
(:head
|
||||||
(:title "Asteroid Radio - Admin Dashboard")
|
(:title "Asteroid Radio - Admin Dashboard")
|
||||||
(:meta :charset "utf-8")
|
(:meta :charset "utf-8")
|
||||||
(:style "
|
(:link :rel "stylesheet" :type "text/css" :href "/static/asteroid.css"))
|
||||||
body { font-family: 'Courier New', monospace; background: #0a0a0a; color: #00ff00; margin: 0; padding: 20px; }
|
|
||||||
.container { max-width: 1200px; margin: 0 auto; }
|
|
||||||
h1 { color: #ff6600; }
|
|
||||||
.panel { background: #1a1a1a; padding: 20px; border: 1px solid #333; margin: 20px 0; }
|
|
||||||
button { background: #333; color: #00ff00; border: 1px solid #555; padding: 10px 20px; margin: 5px; cursor: pointer; }
|
|
||||||
button:hover { background: #555; }
|
|
||||||
.back { color: #00ff00; text-decoration: none; }
|
|
||||||
"))
|
|
||||||
(:body
|
(:body
|
||||||
(:div.container
|
(:div.container
|
||||||
(:a.back :href "/" "← Back to Main")
|
(:a.back :href "/" "← Back to Main")
|
||||||
|
|
@ -110,14 +109,7 @@
|
||||||
(:head
|
(:head
|
||||||
(:title "Asteroid Radio - Web Player")
|
(:title "Asteroid Radio - Web Player")
|
||||||
(:meta :charset "utf-8")
|
(:meta :charset "utf-8")
|
||||||
(:style "
|
(:link :rel "stylesheet" :type "text/css" :href "/static/asteroid.css"))
|
||||||
body { font-family: 'Courier New', monospace; background: #0a0a0a; color: #00ff00; margin: 0; padding: 20px; text-align: center; }
|
|
||||||
.player { background: #1a1a1a; padding: 40px; border: 1px solid #333; margin: 40px auto; max-width: 600px; }
|
|
||||||
.now-playing { font-size: 1.5em; margin: 20px 0; color: #ff6600; }
|
|
||||||
.controls button { background: #333; color: #00ff00; border: 1px solid #555; padding: 15px 30px; margin: 10px; font-size: 1.2em; cursor: pointer; }
|
|
||||||
.controls button:hover { background: #555; }
|
|
||||||
.back { color: #00ff00; text-decoration: none; }
|
|
||||||
"))
|
|
||||||
(:body
|
(:body
|
||||||
(:a.back :href "/" "← Back to Main")
|
(:a.back :href "/" "← Back to Main")
|
||||||
(:div.player
|
(:div.player
|
||||||
|
|
@ -151,6 +143,7 @@
|
||||||
(defun start-server (&key (port *server-port*))
|
(defun start-server (&key (port *server-port*))
|
||||||
"Start the Asteroid Radio RADIANCE server"
|
"Start the Asteroid Radio RADIANCE server"
|
||||||
(format t "Starting Asteroid Radio RADIANCE server on port ~a~%" port)
|
(format t "Starting Asteroid Radio RADIANCE server on port ~a~%" port)
|
||||||
|
(compile-styles) ; Generate CSS file using LASS
|
||||||
(radiance:startup)
|
(radiance:startup)
|
||||||
(format t "Server started! Visit http://localhost:~a/asteroid/~%" port))
|
(format t "Server started! Visit http://localhost:~a/asteroid/~%" port))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,13 @@
|
||||||
#!/usr/local/bin/sbcl --script
|
#!/usr/bin/sbcl --script
|
||||||
;; -*-lisp-*-
|
;; -*-lisp-*-
|
||||||
|
|
||||||
(load "~/quicklisp/setup.lisp")
|
(load "~/quicklisp/setup.lisp")
|
||||||
|
|
||||||
;; Build script for creating asteroid executable using save-lisp-and-die
|
;; Build script for creating asteroid executable using save-lisp-and-die
|
||||||
(require :asdf)
|
;; ASDF will automatically find the project via source-registry.conf
|
||||||
;; Add project directory to ASDF
|
|
||||||
;; (push #P"/home/fade/SourceCode/lisp/asteroid/" asdf:*central-registry*)
|
|
||||||
|
|
||||||
;; Load the system
|
;; Load the system
|
||||||
(ql:quickload "asteroid")
|
(ql:quickload :asteroid)
|
||||||
;; (asdf:load-system :asteroid)
|
|
||||||
|
|
||||||
;; Define the main function for the executable
|
;; Define the main function for the executable
|
||||||
(defun main ()
|
(defun main ()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
body{
|
||||||
|
font-family: Courier New, monospace;
|
||||||
|
background: #0a0a0a;
|
||||||
|
color: #00ff00;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .container{
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
body h1{
|
||||||
|
color: #ff6600;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 2.5em;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body h2{
|
||||||
|
color: #ff6600;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .status{
|
||||||
|
background: #1a1a1a;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #333;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .panel{
|
||||||
|
background: #1a1a1a;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #333;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .nav{
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .nav a{
|
||||||
|
color: #00ff00;
|
||||||
|
text-decoration: none;
|
||||||
|
margin: 0 15px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: 1px solid #333;
|
||||||
|
background: #1a1a1a;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .nav a :hover{
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .controls{
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .controls button{
|
||||||
|
background: #1a1a1a;
|
||||||
|
color: #00ff00;
|
||||||
|
border: 1px solid #333;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .controls button :hover{
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
body button{
|
||||||
|
background: #333;
|
||||||
|
color: #00ff00;
|
||||||
|
border: 1px solid #555;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
body button :hover{
|
||||||
|
background: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .now-playing{
|
||||||
|
background: #1a1a1a;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #333;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 1.5em;
|
||||||
|
color: #ff6600;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .back{
|
||||||
|
color: #00ff00;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .back :hover{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .player{
|
||||||
|
background: #1a1a1a;
|
||||||
|
padding: 40px;
|
||||||
|
border: 1px solid #333;
|
||||||
|
margin: 40px auto;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
body .player .controls button{
|
||||||
|
padding: 15px 30px;
|
||||||
|
margin: 10px;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
body body.player-page{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
;; LASS stylesheet for Asteroid Radio
|
||||||
|
;; Hacker-themed green terminal styling
|
||||||
|
|
||||||
|
(body
|
||||||
|
:font-family "Courier New, monospace"
|
||||||
|
:background "#0a0a0a"
|
||||||
|
:color "#00ff00"
|
||||||
|
:margin 0
|
||||||
|
:padding "20px"
|
||||||
|
|
||||||
|
(.container
|
||||||
|
:max-width "1200px"
|
||||||
|
:margin "0 auto")
|
||||||
|
|
||||||
|
(h1
|
||||||
|
:color "#ff6600"
|
||||||
|
:text-align center
|
||||||
|
:font-size "2.5em"
|
||||||
|
:margin-bottom "30px")
|
||||||
|
|
||||||
|
(h2
|
||||||
|
:color "#ff6600")
|
||||||
|
|
||||||
|
(.status
|
||||||
|
:background "#1a1a1a"
|
||||||
|
:padding "20px"
|
||||||
|
:border "1px solid #333"
|
||||||
|
:margin "20px 0")
|
||||||
|
|
||||||
|
(.panel
|
||||||
|
:background "#1a1a1a"
|
||||||
|
:padding "20px"
|
||||||
|
:border "1px solid #333"
|
||||||
|
:margin "20px 0")
|
||||||
|
|
||||||
|
(.nav
|
||||||
|
:margin "20px 0"
|
||||||
|
(a
|
||||||
|
:color "#00ff00"
|
||||||
|
:text-decoration none
|
||||||
|
:margin "0 15px"
|
||||||
|
:padding "10px 20px"
|
||||||
|
:border "1px solid #333"
|
||||||
|
:background "#1a1a1a"
|
||||||
|
:display inline-block
|
||||||
|
(:hover
|
||||||
|
:background "#333")))
|
||||||
|
|
||||||
|
(.controls
|
||||||
|
:margin "20px 0"
|
||||||
|
(button
|
||||||
|
:background "#1a1a1a"
|
||||||
|
:color "#00ff00"
|
||||||
|
:border "1px solid #333"
|
||||||
|
:padding "10px 20px"
|
||||||
|
:margin "5px"
|
||||||
|
:cursor pointer
|
||||||
|
(:hover
|
||||||
|
:background "#333")))
|
||||||
|
|
||||||
|
(button
|
||||||
|
:background "#333"
|
||||||
|
:color "#00ff00"
|
||||||
|
:border "1px solid #555"
|
||||||
|
:padding "10px 20px"
|
||||||
|
:margin "5px"
|
||||||
|
:cursor pointer
|
||||||
|
(:hover
|
||||||
|
:background "#555"))
|
||||||
|
|
||||||
|
(.now-playing
|
||||||
|
:background "#1a1a1a"
|
||||||
|
:padding "20px"
|
||||||
|
:border "1px solid #333"
|
||||||
|
:margin "20px 0"
|
||||||
|
:font-size "1.5em"
|
||||||
|
:color "#ff6600")
|
||||||
|
|
||||||
|
(.back
|
||||||
|
:color "#00ff00"
|
||||||
|
:text-decoration none
|
||||||
|
:margin-bottom "20px"
|
||||||
|
:display inline-block
|
||||||
|
(:hover
|
||||||
|
:text-decoration underline))
|
||||||
|
|
||||||
|
;; Player-specific styles
|
||||||
|
(.player
|
||||||
|
:background "#1a1a1a"
|
||||||
|
:padding "40px"
|
||||||
|
:border "1px solid #333"
|
||||||
|
:margin "40px auto"
|
||||||
|
:max-width "600px"
|
||||||
|
(.controls
|
||||||
|
(button
|
||||||
|
:padding "15px 30px"
|
||||||
|
:margin "10px"
|
||||||
|
:font-size "1.2em")))
|
||||||
|
|
||||||
|
;; Center alignment for player page
|
||||||
|
(body.player-page
|
||||||
|
:text-align center))
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
;; Test script for Asteroid Radio server
|
|
||||||
(format t "Loading dependencies...~%")
|
|
||||||
(ql:quickload '(:hunchentoot :spinneret :cl-json))
|
|
||||||
|
|
||||||
(format t "Loading Asteroid Radio...~%")
|
|
||||||
(load "asteroid.asd")
|
|
||||||
(asdf:load-system :asteroid)
|
|
||||||
|
|
||||||
;; Start server in non-blocking mode
|
|
||||||
(format t "Starting server...~%")
|
|
||||||
(asteroid:start-server)
|
|
||||||
|
|
||||||
(format t "Testing API endpoint...~%")
|
|
||||||
;; Give server a moment to start
|
|
||||||
(sleep 2)
|
|
||||||
|
|
||||||
(format t "Server should now be running on http://localhost:8080~%")
|
|
||||||
(format t "Try visiting:~%")
|
|
||||||
(format t " - http://localhost:8080/ (main page)~%")
|
|
||||||
(format t " - http://localhost:8080/admin (admin dashboard)~%")
|
|
||||||
(format t " - http://localhost:8080/player (web player)~%")
|
|
||||||
(format t " - http://localhost:8080/api/status (API status)~%")
|
|
||||||
|
|
||||||
(format t "~%Press Enter to stop the server...~%")
|
|
||||||
(read-line)
|
|
||||||
|
|
||||||
(asteroid:stop-server)
|
|
||||||
(format t "Test complete.~%")
|
|
||||||
Loading…
Reference in New Issue