git.fiddlerwoaroof.com
Browse code

Updating userinfo and the feed reading interface

fiddlerwoaroof authored on 04/09/2015 19:02:23
Showing 12 changed files
... ...
@@ -1,2 +1,3 @@
1 1
 *-secrets.json
2 2
 .*.sw?
3
+*.fasl
3 4
new file mode 100644
... ...
@@ -0,0 +1,3 @@
1
+[submodule "colors"]
2
+	path = colors
3
+	url = ./colors
... ...
@@ -1,4 +1,5 @@
1 1
 ;;;; cl-oid-connect.lisp
2
+;;;; TODO: Need to refactor out server names!!!
2 3
 #|
3 4
 |Copyright (c) 2015 Edward Langley
4 5
 |All rights reserved.
... ...
@@ -45,6 +46,7 @@
45 46
                                 :properties '((auth-endpoint nil :accessor auth-endpoint)
46 47
                                               (token-endpoint nil :accessor token-endpoint)
47 48
                                               (userinfo-endpoint nil :accessor t)
49
+                                              (auth-scope "openid profile email" :accessor t)
48 50
                                               (redirect-uri nil :accessor t))))
49 51
 (sheeple:defmessage get-user-info (a b))
50 52
 (sheeple:defmessage get-access-token (a b))
... ...
@@ -67,6 +69,7 @@
67 69
           ((auth-endpoint "https://www.facebook.com/dialog/oauth")
68 70
            (token-endpoint "https://graph.facebook.com/v2.3/oauth/access_token")
69 71
            (userinfo-endpoint "https://graph.facebook.com/v2.3/me")
72
+           (auth-scope "email")
70 73
            (redirect-uri  "http://srv2.elangley.org:9090/oidc_callback/facebook")))
71 74
 
72 75
 (sheeple:defreply get-access-token ((endpoint-schema *fbook-endpoint-schema*) (code sheeple:=string=))
... ...
@@ -97,6 +100,7 @@
97 100
 
98 101
     (setf (auth-endpoint schema) (assoc-cdr :authorization--endpoint discovery-document))
99 102
     (setf (token-endpoint schema) (assoc-cdr :token--endpoint discovery-document))
103
+    (setf (userinfo-endpoint schema) (assoc-cdr :userinfo--endpoint discovery-document))
100 104
 
101 105
     (if gui-p (sheeple:defreply get-user-info ((a schema)) (funcall gui a)))
102 106
     (if gat-p (sheeple:defreply get-access-token ((a schema) (b sheeple:=string=))
... ...
@@ -116,7 +120,7 @@
116 120
                        :parameters `(("client_id" . ,(client-id endpoint-schema))
117 121
                                      ("app_id" . ,(client-id endpoint-schema))
118 122
                                      ("response_type" . "code")
119
-                                     ("scope" . "email")
123
+                                     ("scope" . ,(auth-scope endpoint-schema))
120 124
                                      ("redirect_uri" . ,(redirect-uri endpoint-schema))
121 125
                                      ("state" . ,state))))
122 126
 
... ...
@@ -163,7 +167,7 @@
163 167
     (let* ((data (yason:parse fbook-info))
164 168
            (client-id (gethash "client-id" data))
165 169
            (secret (gethash "secret" data)))
166
-      (setf (client-id *FBOOK-INFO*) client-id) 
170
+      (setf (client-id *FBOOK-INFO*) client-id)
167 171
       (setf (secret *FBOOK-INFO*) secret))))
168 172
 
169 173
 (defun load-google-info (loadfrom)
... ...
@@ -191,6 +195,15 @@
191 195
                       :gat #'goog-get-access-token)
192 196
   (setf (redirect-uri *goog-endpoint-schema*)   "http://srv2.elangley.org:9090/oidc_callback/google"))
193 197
 
198
+(sheeple:defreply get-user-info ((endpoint-schema *goog-endpoint-schema*) (access-token sheeple:=string=))
199
+  (format t "getting user data: ~a~%" "blarg")
200
+  (let ((endpoint (userinfo-endpoint endpoint-schema)))
201
+    (cl-json:decode-json-from-string
202
+      (drakma:http-request endpoint
203
+                           :parameters `(("alt" . "json")
204
+                                         ("access_token" . ,access-token))
205
+                           ))))
206
+
194 207
 
195 208
 (defun oauth2-login-middleware (&key google-info facebook-info)
196 209
   (let ((clack-env nil))
... ...
@@ -200,16 +213,16 @@
200 213
       (load-goog-endpoint-schema)
201 214
       (load-google-info google-info)
202 215
 
203
-    (def-route ("/login/google" (params) :app app)
204
-      (with-context-variables (session)
205
-        (let ((state (gen-state 36)))
206
-          (setf (gethash :state session) state)
207
-          (with-endpoints *goog-endpoint-schema*
208
-            (setf (gethash :endpoint-schema session) *goog-endpoint-schema*)
209
-            (multiple-value-bind (content rcode headers) (do-auth-request *goog-endpoint-schema* state)
210
-              (if (< rcode 400)
211
-                `(302 (:location ,(cdr (assoc :location headers))))
212
-                content))))))
216
+      (def-route ("/login/google" (params) :app app)
217
+        (with-context-variables (session)
218
+          (let ((state (gen-state 36)))
219
+            (setf (gethash :state session) state)
220
+            (with-endpoints *goog-endpoint-schema*
221
+              (setf (gethash :endpoint-schema session) *goog-endpoint-schema*)
222
+              (multiple-value-bind (content rcode headers) (do-auth-request *goog-endpoint-schema* state)
223
+                (if (< rcode 400)
224
+                  `(302 (:location ,(cdr (assoc :location headers))))
225
+                  content))))))
213 226
 
214 227
 
215 228
     (def-route ("/login/facebook" (params) :app app)
... ...
@@ -231,10 +244,14 @@
231 244
                      (with-context-variables (session)
232 245
                        (with-endpoints *goog-endpoint-schema*
233 246
                          (let* ((a-t (get-access-token *goog-endpoint-schema* code))
247
+                                (access-token (assoc-cdr :access--token a-t)) ;; Argh
234 248
                                 (id-token (assoc-cdr :id--token a-t))
235 249
                                 (decoded (cljwt:decode id-token :fail-if-unsupported nil)))
236
-                           (setf (gethash :userinfo session) decoded)
237
-                           '(302 (:location "/")))))
250
+                           (setf (gethash :idtoken session) (get-user-info *goog-endpoint-schema* id-token))
251
+                           (setf (gethash :accesstoken session) (get-user-info *goog-endpoint-schema* access-token))
252
+                           (setf (gethash :userinfo session) (get-user-info *goog-endpoint-schema* access-token))
253
+                           '(302 (:location "/"))
254
+                           )))
238 255
                      '(403 '() "Out, vile imposter!"))))
239 256
 
240 257
 
... ...
@@ -252,7 +269,7 @@
252 269
 
253 270
     (def-route ("/userinfo.json" (params) :app app)
254 271
       (with-context-variables (session)
255
-        (require-login 
272
+        (require-login
256 273
           (with-endpoints  (gethash :endpoint-schema session)
257 274
             (cl-json:encode-json-to-string (gethash :userinfo session))))))
258 275
 
259 276
new file mode 160000
... ...
@@ -0,0 +1 @@
1
+Subproject commit b203d4f1b4abdc5c72582d6e6465e7eebe5fec0e
0 2
deleted file mode 100644
... ...
@@ -1 +0,0 @@
1
-This is the stub README.txt for the "colors" project.
2 0
deleted file mode 100644
... ...
@@ -1,9 +0,0 @@
1
-;;;; colors.asd
2
-
3
-(asdf:defsystem #:colors
4
-  :description "Describe colors here"
5
-  :author "Your Name <your.name@example.com>"
6
-  :license "Specify license here"
7
-  :serial t
8
-  :components ((:file "colors")))
9
-
10 0
deleted file mode 100644
... ...
@@ -1,111 +0,0 @@
1
-;;;; colors.lisp
2
-(defpackage #:colors
3
-  (:use #:cl)
4
-  (:export #:colorscheme #:palette *palette*
5
-           #:invert-palette
6
-           #:let-palette #:with-palette
7
-           #:accentize
8
-           #:colorscheme-bg #:colorscheme-bg-highlight 
9
-           #:colorscheme-fg-deemph #:colorscheme-fg #:colorscheme-fg-highlight 
10
-           #:colorscheme-accent 
11
-           #:colorscheme-hover-highlight))
12
-
13
-(in-package #:colors)
14
-(declaim (optimize (debug 2) (safety 2) (speed 0)))
15
-
16
-;;; Generic utility macro TODO: separate these out!!!
17
-(defmacro initialize-to (obj1-v obj2-v &body slot-swaps)
18
-  (alexandria:with-gensyms (obj1 obj2)
19
-    `(let* ((,obj1 ,obj1-v)
20
-            (,obj2 ,obj2-v))
21
-       ,@(loop for (to from) in slot-swaps
22
-               collect `(setf (,to ,obj1) (,from ,obj2))))))
23
-
24
-;;; This macro connects the "-" prefixed slots in the colorscheme class
25
-;;; To the appropriate palette
26
-(defmacro def-palette-accessor (scheme-slot scheme palette )
27
-  `(progn
28
-     (defgeneric ,scheme-slot (,scheme))
29
-     (defmethod ,scheme-slot ((,scheme colorscheme))
30
-       (slot-value ,palette (,(intern (concatenate 'string "-" (symbol-name scheme-slot))) ,scheme)))))
31
-
32
-
33
-;; &group interfaces
34
-;;; Palette class and methods &group
35
-
36
-(defclass palette () ; solarized http://ethanschoonover.com/solarized
37
-  ((base03     :accessor palette-base03      :initform "#002b36")
38
-   (base02     :accessor palette-base02      :initform "#073642")
39
-   (base01     :accessor palette-base01      :initform "#586e75")
40
-   (base00     :accessor palette-base00      :initform "#657b83")
41
-   (base0      :accessor palette-base0       :initform "#839496")
42
-   (base1      :accessor palette-base1       :initform "#93a1a1")
43
-   (base2      :accessor palette-base2       :initform "#eee8d5")
44
-   (base3      :accessor palette-base3       :initform "#fdf6e3")
45
-   (yellow     :accessor palette-yellow      :initform "#b58900")
46
-   (orange     :accessor palette-orange      :initform "#cb4b16")
47
-   (red        :accessor palette-red         :initform "#dc322f")
48
-   (magenta    :accessor palette-magenta     :initform "#d33682")
49
-   (violet     :accessor palette-violet      :initform "#6c71c4")
50
-   (blue       :accessor palette-blue        :initform "#268bd2")
51
-   (cyan       :accessor palette-cyan        :initform "#2aa198")
52
-   (green      :accessor palette-green       :initform "#859900")))
53
-
54
-(defgeneric invert-palette (palette))
55
-
56
-;;; The palette var: this defaults to the solarized palette defined
57
-;;; above, but can (and should) be temporarily rebound via the 
58
-;;; with-palette macro below.
59
-(defparameter *palette* (make-instance 'palette))
60
-
61
-(defmacro let-palette (palette &body body)
62
-  "Set custom palette in end-user code"
63
-  `(let ((*palette* ,palette))
64
-     ,@body))
65
-
66
-(defmacro with-palette ((place) &body body)
67
-  "Access the current palette"
68
-  `(let ((,place *palette*))
69
-     ,@body))
70
-
71
-;;; &endgroup
72
-;;; &group Color scheme
73
-(defclass colorscheme ()
74
-  ((bg           :accessor -colorscheme-bg           :initform 'base03)
75
-   (bg-highlight :accessor -colorscheme-bg-highlight :initform 'base02)
76
-   (fg-deemph    :accessor -colorscheme-fg-deemph    :initform 'base01)
77
-   (fg           :accessor -colorscheme-fg           :initform 'base0 )
78
-   (fg-highlight :accessor -colorscheme-fg-highlight :initform 'base1 )
79
-   (hover-highlight :accessor -colorscheme-hover-highlight :initform 'base3 )
80
-   (accent       :accessor -colorscheme-accent       :initform 'violet)))
81
-
82
-(defgeneric accentize (colorscheme accent))
83
-
84
-(def-palette-accessor colorscheme-bg               scheme *palette*)
85
-(def-palette-accessor colorscheme-bg-highlight     scheme *palette*)
86
-(def-palette-accessor colorscheme-fg-deemph        scheme *palette*)
87
-(def-palette-accessor colorscheme-fg               scheme *palette*)
88
-(def-palette-accessor colorscheme-fg-highlight     scheme *palette*)
89
-(def-palette-accessor colorscheme-accent           scheme *palette*)
90
-(def-palette-accessor colorscheme-hover-highlight  scheme *palette*)
91
-
92
-;;; &endgroup
93
-;; &endgroup
94
-
95
-(defmethod invert-palette ((palette palette))
96
-  (let ((result (make-instance 'palette)))
97
-    (initialize-to result palette
98
-      (palette-base03 palette-base3)
99
-      (palette-base02 palette-base2)
100
-      (palette-base01 palette-base1)
101
-      (palette-base00 palette-base0)
102
-      (palette-base0  palette-base00)
103
-      (palette-base1  palette-base01)
104
-      (palette-base2  palette-base02)
105
-      (palette-base3  palette-base03))
106
-    result))
107
-
108
-(defmethod accentize ((colorscheme colorscheme) accent)
109
-  (setf (colorscheme-accent colorscheme) (funcall accent colorscheme)))
110
-
111
-; vim: foldmethod=marker foldmarker=&group,&endgroup foldlevel=0 :
112 0
deleted file mode 100644
... ...
@@ -1,2 +0,0 @@
1
-;;;; package.lisp
2
-
... ...
@@ -1,25 +1,39 @@
1 1
 (in-package :cl-user)
2
-(ql:quickload :plump)
3
-(ql:quickload :lquery)
4 2
 (ql:quickload :cl-markup)
5 3
 (ql:quickload :cl-oid-connect)
6 4
 (ql:quickload :colors)
5
+(ql:quickload :lquery)
6
+(ql:quickload :plump)
7
+(ql:quickload :postmodern)
7 8
 
8 9
 (push (cons "application" "rdf+xml") drakma:*text-content-types*)
9 10
 (push (cons "application" "rss+xml") drakma:*text-content-types*)
10 11
 (push (cons "text" "rss+xml") drakma:*text-content-types*)
11 12
 
13
+(lquery:define-lquery-list-function tag-name (nodes &rest tags)
14
+  "Manipulate elements on the basis of there tag-name.
15
+   With no arguments, return their names else return
16
+   the corresponding tags."
17
+  (if (null tags)
18
+    (map 'vector #'plump:tag-name nodes)
19
+    (apply #'vector
20
+           (loop for node across nodes
21
+                 if (find (plump:tag-name node) tags :test #'string=)
22
+                 collect node))))
23
+
12 24
 (defparameter *app* (make-instance 'ningle:<app>))
13 25
 
14 26
 (defclass rss-feed ()
15
-  ((feed :accessor rss-feed-feed
16
-         :initarg :feed)
27
+  ((feed :accessor rss-feed-feed :initarg :feed)
17 28
    (channel :accessor rss-feed-channel)
18 29
    (title :accessor rss-feed-title)
19 30
    (link :accessor rss-feed-link)
20 31
    (description :accessor rss-feed-description)
21 32
    (items :accessor rss-feed-items)))
22 33
 
34
+(defgeneric serialize (cls))
35
+
36
+
23 37
 (defclass rss-item ()
24 38
   ((item :accessor rss-item-item  :initarg :item)
25 39
    (title :accessor rss-item-title)
... ...
@@ -33,6 +47,10 @@
33 47
    (pub-date :accessor rss-item-pub-date)
34 48
    (source :accessor rss-item-source)))
35 49
 
50
+(defmethod serialize ((obj rss-feed))
51
+  (postmodern:make-dao 'rss)
52
+  )
53
+
36 54
 (defmacro get-elements (feed &optional (filter nil))
37 55
   (let ((feed-sym (gensym))
38 56
         (filter-lis `(lambda (x) (and (plump-dom:element-p x) ,@(loop for x in filter
... ...
@@ -44,11 +62,7 @@
44 62
   `(get-elements ,feed ((lambda (x) (string= ,tagname (plump:tag-name x))))))
45 63
 
46 64
 (defmacro extract-text (selector &optional (default ""))
47
-  (alexandria:with-gensyms (selector-s)
48
-    `(let ((,selector-s ,selector))
49
-       (if (not (equalp #() (lquery:$ ,selector-s)))
50
-         (lquery:$ ,selector-s (text) (node))
51
-         ,default))))
65
+  `(or (lquery:$ ,selector (text) (node)) ,default))
52 66
 
53 67
 (defun make-rss-item (item)
54 68
   (lquery:initialize item)
... ...
@@ -98,7 +112,7 @@
98 112
 (defun make-rss-feed (feed)
99 113
   (lquery:initialize feed)
100 114
   (let* ((result (make-instance 'rss-feed :feed feed))
101
-         (channel (lquery:$ "channel" (text) (node)))
115
+         (channel (lquery:$ "channel" (node)))
102 116
          (title (lquery:$  "title" (text) (node)))
103 117
          (link (lquery:$ "link" (text) (node)))
104 118
          (description (lquery:$ "description" (text) (node)))
... ...
@@ -125,17 +139,6 @@
125 139
           :class "login-button google"
126 140
           (:a :href "/login/google" "Google"))))))
127 141
 
128
-(lquery:define-lquery-list-function tag-name (nodes &rest tags)
129
-  "Manipulate elements on the basis of there tag-name.
130
-   With no arguments, return their names else return
131
-   the corresponding tags."
132
-  (if (null tags)
133
-    (map 'vector #'plump:tag-name nodes)
134
-    (apply #'vector
135
-           (loop for node across nodes
136
-                 if (find (plump:tag-name node) tags :test #'string=) 
137
-                 collect node))))
138
-
139 142
 (defparameter *feed-urls*
140 143
   #(
141 144
     "http://www.reddit.com/r/lisp.rss"
... ...
@@ -157,109 +160,6 @@
157 160
 
158 161
 (defparameter *feeds* (map 'vector (lambda (x) (unwind-protect (make-rss-feed x))) *docs*))
159 162
 
160
-;;; this will be bound by calls to with-palette
161
-;;; probably should be refactored out
162
-(defparameter *palette* nil)
163
-
164
-(defparameter *colorscheme* (make-instance 'colors:colorscheme))
165
-
166
-(cl-oid-connect:def-route ("/theme/dark.css" (params) :app *app*)
167
-  (colors:let-palette (make-instance 'colors:palette)
168
-    (eval '(get-theme-css))))
169
-
170
-(cl-oid-connect:def-route ("/theme/light.css" (params) :app *app*)
171
-  (colors:let-palette (colors:invert-palette (make-instance 'colors:palette))
172
-    (eval '(get-theme-css))))
173
-
174
-(defun get-theme-css ()
175
-  (colors:with-palette (*palette*)
176
-    (flet ((combine-unit-q (quant unit) (format nil "~d~a" quant unit)))
177
-      (let* ((header-height 9)
178
-             (height-units "vh")
179
-             (ss (lass:compile-and-write
180
-                   `(* :color ,(colors:colorscheme-fg *colorscheme*))
181
-
182
-                 `(body :background-color ,(colors:colorscheme-bg *colorscheme*))
183
-
184
-                 `((:or h1 h2 h3)
185
-                   :color ,(colors:colorscheme-fg-highlight *colorscheme*))
186
-                 `(.feed-header
187
-                    :background-color ,(colors:colorscheme-bg-highlight *colorscheme*))
188
-
189
-                 `((:or h4 h5 h6) :color ,(colors:colorscheme-fg-highlight *colorscheme*))
190
-
191
-                 `(header
192
-                    :border-bottom "thin" "solid" ,(colors:colorscheme-accent *colorscheme*)
193
-                    :height ,(combine-unit-q header-height height-units)
194
-                    :font-size ,(combine-unit-q (* 0.75 header-height) height-units)
195
-                    :line-height ,(combine-unit-q header-height height-units)
196
-                    (.flip-button
197
-                      :float right
198
-                      :width "3em"
199
-                      :height "3em"
200
-                      :padding-left "1em"
201
-                      :padding-bottom "1em"
202
-                      :border-bottom-left-radius "100%"
203
-                      :border none
204
-                      :transition "all 0.5s ease"
205
-                      :background-color ,(colors:colorscheme-fg *colorscheme*)
206
-                      :color ,(colors:colorscheme-bg *colorscheme*))
207
-                    ((:and .flip-button :focus)
208
-                     :outline none)
209
-                    ((:and .flip-button :hover)
210
-                     :width "4em"
211
-                     :height "4em"
212
-                     :padding-left "2em"
213
-                     :padding-bottom "2em")
214
-                    )
215
-
216
-                 `(main
217
-                    :border-left thin solid ,(colors:colorscheme-accent *colorscheme*)
218
-                    :height ,(combine-unit-q (- 100 header-height) height-units))
219
-
220
-                 `((:or a (:and a :visited) (:and a :active) code.url)
221
-                   :color ,(colors:colorscheme-fg-highlight *colorscheme*))
222
-
223
-                 `(section#sidebar
224
-                    (ul.menu
225
-                      ((li + li)
226
-                       :border-top "thin" "solid" ,(colors:colorscheme-fg-highlight *colorscheme*))
227
-                      ((:and li :hover)
228
-                       :background-color ,(colors:colorscheme-hover-highlight *colorscheme*)
229
-                       :color ,(colors:colorscheme-fg-highlight *colorscheme*))))
230
-
231
-                 `(.feed
232
-                    :border-bottom thin solid ,(colors:colorscheme-fg *colorscheme*)
233
-                    :border-left none)
234
-
235
-                 `(.link-header :background-color ,(colors:colorscheme-bg-highlight *colorscheme*))
236
-                 `(.link
237
-                    :border-top thin solid ,(colors:colorscheme-fg *colorscheme*)
238
-                    :border-bottom none
239
-
240
-
241
-                    (.link-info
242
-                      :color ,(colors:colorscheme-fg-deemph *colorscheme*)
243
-                      :border-bottom "thin" "solid" ,(colors:colorscheme-fg *colorscheme*)
244
-                      ((:or a span)
245
-                       :color inherit)
246
-                      ((:and a :hover)
247
-                       :color ,(colors:colorscheme-fg *colorscheme*))
248
-                      ))
249
-                 `((:and .feed-header :hover)
250
-                   :background-color ,(colors:colorscheme-hover-highlight *colorscheme*))
251
-                 `((.link.closed .link-header)
252
-                   :background-color ,(colors:colorscheme-bg *colorscheme*))
253
-
254
-                 `((:or (:and .link-header :hover) (.link.closed (:and .link-header)))
255
-                  :background-color ,(colors:colorscheme-hover-highlight *colorscheme*))
256
-                 `(blah
257
-                    :a ,(colors:colorscheme-fg-highlight *colorscheme*)
258
-                    :a ,(colors:colorscheme-hover-highlight *colorscheme*)
259
-                    :a ,(colors:colorscheme-bg-highlight *colorscheme*)
260
-                    )
261
-                 )))
262
-      `(200 (:content-type "text/css") ,ss)))))
263 163
 
264 164
 (defmacro item-markup (item)
265 165
   (alexandria:with-gensyms (item-s)
... ...
@@ -313,7 +213,7 @@
313 213
        (:link :rel "stylesheet" :href "/theme/light.css"))
314 214
      (:body
315 215
        (:header
316
-         (:button :class "flip-button" ">") 
216
+         (:button :class "flip-button" ">")
317 217
          (:h1 "What?")
318 218
          )
319 219
        (:section :id "content"
... ...
@@ -354,10 +254,113 @@
354 254
 (cl-oid-connect:def-route ("/" (params) :app *app*)
355 255
   (ningle.context:with-context-variables (session)
356 256
       ;(cl-oid-connect:require-login
357
-        (let ((*feeds* (gethash :feeds session *feeds*)))
358
-          (base-template-f));)
257
+        (cl-oid-connect:redirect-if-necessary session
258
+          (let ((*feeds* (gethash :feeds session *feeds*)))
259
+          (base-template-f)));)
359 260
   ))
360 261
 
262
+;;; this will be bound by calls to with-palette
263
+;;; probably should be refactored out
264
+(defparameter *palette* nil)
265
+
266
+(defparameter *colorscheme* (make-instance 'colors:colorscheme))
267
+
268
+(cl-oid-connect:def-route ("/theme/dark.css" (params) :app *app*)
269
+  (colors:let-palette (make-instance 'colors:palette)
270
+    (eval '(get-theme-css))))
271
+
272
+(cl-oid-connect:def-route ("/theme/light.css" (params) :app *app*)
273
+  (colors:let-palette (colors:invert-palette (make-instance 'colors:palette))
274
+    (eval '(get-theme-css))))
275
+
276
+
277
+
278
+(defun get-theme-css ()
279
+  (colors:with-palette (*palette*)
280
+    (flet ((combine-unit-q (quant unit) (format nil "~d~a" quant unit)))
281
+      (let* ((header-height 9)
282
+             (height-units "vh")
283
+             (ss (lass:compile-and-write
284
+                   `(* :color ,(colors:colorscheme-fg *colorscheme*))
285
+
286
+                   `(body :background-color ,(colors:colorscheme-bg *colorscheme*))
287
+
288
+                   `((:or h1 h2 h3)
289
+                     :color ,(colors:colorscheme-fg-highlight *colorscheme*))
290
+                   `(.feed-header
291
+                      :background-color ,(colors:colorscheme-bg-highlight *colorscheme*))
292
+
293
+                   `((:or h4 h5 h6) :color ,(colors:colorscheme-fg-highlight *colorscheme*))
294
+
295
+                   `(header
296
+                      :border-bottom "thin" "solid" ,(colors:colorscheme-accent *colorscheme*)
297
+                      :height ,(combine-unit-q header-height height-units)
298
+                      :font-size ,(combine-unit-q (* 0.75 header-height) height-units)
299
+                      :line-height ,(combine-unit-q header-height height-units)
300
+                      (.flip-button
301
+                        :float right
302
+                        :width "3em"
303
+                        :height "3em"
304
+                        :padding-left "1em"
305
+                        :padding-bottom "1em"
306
+                        :border-bottom-left-radius "100%"
307
+                        :border none
308
+                        :transition "all 2s cubic-bezier(0.175, 0.885, 0.32, 1.275)"
309
+                        :background-color ,(colors:colorscheme-fg *colorscheme*)
310
+                        :color ,(colors:colorscheme-bg *colorscheme*))
311
+                      ((:and .flip-button :focus)
312
+                       :outline none)
313
+                      ((:and .flip-button :hover)
314
+                       :width "6em"
315
+                       :height "6em"
316
+                       :padding-left "4em"
317
+                       :padding-bottom "3em")
318
+                      )
319
+
320
+                   `(main
321
+                      :border-left thin solid ,(colors:colorscheme-accent *colorscheme*)
322
+                      :height ,(combine-unit-q (- 100 header-height) height-units))
323
+
324
+                   `((:or a (:and a :visited) (:and a :active) code.url)
325
+                     :color ,(colors:colorscheme-fg-highlight *colorscheme*))
326
+
327
+                   `(section#sidebar
328
+                      (ul.menu
329
+                        ((li + li)
330
+                         :border-top "thin" "solid" ,(colors:colorscheme-fg-highlight *colorscheme*))
331
+                        ((:and li :hover)
332
+                         :background-color ,(colors:colorscheme-hover-highlight *colorscheme*)
333
+                         :color ,(colors:colorscheme-fg-highlight *colorscheme*))))
334
+
335
+                   `(.feed
336
+                      :border-bottom thick solid ,(colors:colorscheme-accent *colorscheme*)
337
+                      :border-left none)
338
+
339
+                   `(.link-header :background-color ,(colors:colorscheme-bg-highlight *colorscheme*))
340
+                   `(.link
341
+                      :border-top thin solid ,(colors:colorscheme-fg *colorscheme*)
342
+                      :border-bottom none
343
+
344
+
345
+                      (.link-info
346
+                        :color ,(colors:colorscheme-fg-deemph *colorscheme*)
347
+                        :border-bottom "thin" "solid" ,(colors:colorscheme-fg *colorscheme*)
348
+                        ((:or a span)
349
+                         :color inherit)
350
+                        ((:and a :hover)
351
+                         :color ,(colors:colorscheme-fg *colorscheme*))
352
+                        ))
353
+                   
354
+                   `((:and .feed-header :hover)
355
+                     :background-color ,(colors:colorscheme-hover-highlight *colorscheme*))
356
+
357
+                   `((.link.closed .link-header)
358
+                     :background-color ,(colors:colorscheme-bg *colorscheme*))
359
+
360
+                   `((:or (:and .link-header :hover) (.link.closed (:and .link-header :hover)))
361
+                     :background-color ,(colors:colorscheme-hover-highlight *colorscheme*)))))
362
+        `(200 (:content-type "text/css") ,ss)))))
363
+
361 364
 (defvar *handler* nil)
362 365
 
363 366
 (defun stop ()
... ...
@@ -11,6 +11,7 @@
11 11
   :padding "0px")
12 12
 
13 13
 (body
14
+  :transition "background-color 0.25s ease"
14 15
   :font-family "Lato")
15 16
 
16 17
 (((:or main "#sidebar" .feed) > (:or ul ol))
... ...
@@ -53,13 +54,14 @@
53 54
     :font-variant small-caps
54 55
     (li
55 56
       (a
56
-        :width "100%"
57
+        :color inherit
57 58
         :display block
59
+        :font-size "125%"
60
+        :font-weight 700
58 61
         :padding "0.5em"
59
-        :color inherit
60 62
         :text-decoration none
61
-        :font-weight 700
62
-        :font-size "125%"
63
+        :transition "background-color 0.25s ease"
64
+        :width "100%"
63 65
         ))))
64 66
 
65 67
 (main
... ...
@@ -73,6 +75,7 @@
73 75
   ((:or h2 h3) :padding "0.62em")
74 76
   (h2 :padding-bottom "0.38em")
75 77
   (h3 :padding-top "0.38em")
78
+  :transition "background-color 0.25s ease"
76 79
   :padding-bottom "0em")
77 80
 
78 81
 ((.link.closed .link-content) 
... ...
@@ -91,6 +94,7 @@
91 94
     :padding "1em"
92 95
     :padding-bottom "0em"
93 96
     :cursor pointer
97
+    :transition "background-color 0.25s ease"
94 98
     (h4
95 99
       :margin-bottom "0.5em"
96 100
       :display "inline-block")) 
... ...
@@ -1 +1 @@
1
-@import url(https://fonts.googleapis.com/css?family=Lato:400,100,300,400italic,300italic,700,700italic,900&subset=latin,latin-ext);@import url(https://fonts.googleapis.com/css?family=Caudex);.feed,main{-webkit-backface-visibility:hidden;-webkit-transform:translateZ(0);}*{box-sizing:border-box;margin:0px;padding:0px;}body{font-family:Lato;}main > ul,main > ol,#sidebar > ul,#sidebar > ol,.feed > ul,.feed > ol{list-style:none;margin:0px;}ul{margin:1em;}h1,h2{font-size:153.9%;}:h3{font-size:146.5%;}h4,h5,h6{font-size:138.5%;}ul + h1,ul + h2,ul + h3,ul + h4,ul + h5,ul + h6{width:initial;}header{color:white;}header h1{font-family:Caudex;font-size:inherit;margin-top:0em;padding-left:10vw;font-weight:200;}#sidebar,main{border-top:none;}section#sidebar{width:38vw;height:90vh;position:fixed;overflow:auto;}section#sidebar ul.menu{text-align:right;font-variant:small-caps;}section#sidebar ul.menu li a{width:100%;display:block;padding:0.5em;color:inherit;text-decoration:none;font-weight:700;font-size:125%;}main{width:62vw;float:right;clear:right;overflow-x:hidden;overflow-y:scroll;}.feed-header{padding-bottom:0em;}.feed-header h2,.feed-header h3{padding:0.62em;}.feed-header h2{padding-bottom:0.38em;}.feed-header h3{padding-top:0.38em;}.link.closed .link-content{max-height:0px;padding:0em;}.link.closed{padding-bottom:0em;}.link{text-decoration:none;display:block;overflow:hidden;font-size:0.8em;}.link .link-header{padding:1em;padding-bottom:0em;cursor:pointer;}.link .link-header h4{margin-bottom:0.5em;display:inline-block;}.link .link-info{margin-left:-1em;margin-right:-1em;padding-left:1em;padding-right:1em;padding-bottom:0.32em;}.link .link-info .link-url{float:left;}.link .link-info .link-date{float:right;display:block;}.link .link-info:after{content:" ";display:block;clear:both;}.link .link-content{-moz-transition:max-height 0.5s ease;-o-transition:max-height 0.5s ease;-webkit-transition:max-height 0.5s ease;-ms-transition:max-height 0.5s ease;transition:max-height 0.5s ease;}.link .link-content > div{padding:1em;}.feed.closed .post-list{max-height:0px;padding:0em;}.feed:first-child{border-top:none;}.feed{overflow:hidden;}.feed .post-list{-moz-transition:max-height 0.5s ease;-o-transition:max-height 0.5s ease;-webkit-transition:max-height 0.5s ease;-ms-transition:max-height 0.5s ease;transition:max-height 0.5s ease;}
2 1
\ No newline at end of file
2
+@import url(https://fonts.googleapis.com/css?family=Lato:400,100,300,400italic,300italic,700,700italic,900&subset=latin,latin-ext);@import url(https://fonts.googleapis.com/css?family=Caudex);.feed,main{-webkit-backface-visibility:hidden;-webkit-transform:translateZ(0);}*{box-sizing:border-box;margin:0px;padding:0px;}body{-moz-transition:background-color 0.25s ease;-o-transition:background-color 0.25s ease;-webkit-transition:background-color 0.25s ease;-ms-transition:background-color 0.25s ease;transition:background-color 0.25s ease;font-family:Lato;}main > ul,main > ol,#sidebar > ul,#sidebar > ol,.feed > ul,.feed > ol{list-style:none;margin:0px;}ul{margin:1em;}h1,h2{font-size:153.9%;}:h3{font-size:146.5%;}h4,h5,h6{font-size:138.5%;}ul + h1,ul + h2,ul + h3,ul + h4,ul + h5,ul + h6{width:initial;}header{color:white;}header h1{font-family:Caudex;font-size:inherit;margin-top:0em;padding-left:10vw;font-weight:200;}#sidebar,main{border-top:none;}section#sidebar{width:38vw;height:90vh;position:fixed;overflow:auto;}section#sidebar ul.menu{text-align:right;font-variant:small-caps;}section#sidebar ul.menu li a{color:inherit;display:block;font-size:125%;font-weight:700;padding:0.5em;text-decoration:none;-moz-transition:background-color 0.25s ease;-o-transition:background-color 0.25s ease;-webkit-transition:background-color 0.25s ease;-ms-transition:background-color 0.25s ease;transition:background-color 0.25s ease;width:100%;}main{width:62vw;float:right;clear:right;overflow-x:hidden;overflow-y:scroll;}.feed-header{-moz-transition:background-color 0.25s ease;-o-transition:background-color 0.25s ease;-webkit-transition:background-color 0.25s ease;-ms-transition:background-color 0.25s ease;transition:background-color 0.25s ease;padding-bottom:0em;}.feed-header h2,.feed-header h3{padding:0.62em;}.feed-header h2{padding-bottom:0.38em;}.feed-header h3{padding-top:0.38em;}.link.closed .link-content{max-height:0px;padding:0em;}.link.closed{padding-bottom:0em;}.link{text-decoration:none;display:block;overflow:hidden;font-size:0.8em;}.link .link-header{padding:1em;padding-bottom:0em;cursor:pointer;-moz-transition:background-color 0.25s ease;-o-transition:background-color 0.25s ease;-webkit-transition:background-color 0.25s ease;-ms-transition:background-color 0.25s ease;transition:background-color 0.25s ease;}.link .link-header h4{margin-bottom:0.5em;display:inline-block;}.link .link-info{margin-left:-1em;margin-right:-1em;padding-left:1em;padding-right:1em;padding-bottom:0.32em;}.link .link-info .link-url{float:left;}.link .link-info .link-date{float:right;display:block;}.link .link-info:after{content:" ";display:block;clear:both;}.link .link-content{-moz-transition:max-height 0.5s ease;-o-transition:max-height 0.5s ease;-webkit-transition:max-height 0.5s ease;-ms-transition:max-height 0.5s ease;transition:max-height 0.5s ease;}.link .link-content > div{padding:1em;}.feed.closed .post-list{max-height:0px;padding:0em;}.feed:first-child{border-top:none;}.feed{overflow:hidden;}.feed .post-list{-moz-transition:max-height 0.5s ease;-o-transition:max-height 0.5s ease;-webkit-transition:max-height 0.5s ease;-ms-transition:max-height 0.5s ease;transition:max-height 0.5s ease;}
3 3
\ No newline at end of file
4 4
new file mode 100644
... ...
@@ -0,0 +1,50 @@
1
+(ql:quickload :postmodern)
2
+
3
+(defclass rss-feed-store ()
4
+  ((id          :col-type serial :initarg :id          :accessor rfs-id)
5
+   (title       :col-type text   :initarg :title       :accessor rss-feed-title       :col-default "")
6
+   (link        :col-type text   :initarg :link        :accessor rss-feed-line        :col-default "")
7
+   (description :col-type text   :initarg :description :accessor rss-feed-description :col-default ""))
8
+  (:metaclass postmodern:dao-class)
9
+  (:table-name "rssFeed")
10
+  (:unique link)
11
+  (:keys id))
12
+
13
+(postmodern:deftable rss-feed-store
14
+  (postmodern:!dao-def))
15
+
16
+; (postmodern:create-table 'rss-feed-store)
17
+
18
+(defclass rss-item-store ()
19
+  ((id          :col-type serial  :initarg :id          :accessor ris-id)
20
+   (title       :col-type text    :initarg :title       :accessor ris-title       :col-default "")
21
+   (link        :col-type text    :initarg :link        :accessor ris-link        :col-default "")
22
+   (description :col-type text    :initarg :description :accessor ris-description :col-default "")
23
+   (comments    :col-type text    :initarg :comments    :accessor ris-comments    :col-default "")
24
+   (enclosure   :col-type text    :initarg :enclosure   :accessor ris-enclosure   :col-default "")
25
+   (guid        :col-type text    :initarg :guid        :accessor ris-guid        :col-default "")
26
+   (pub-date    :col-type text    :initarg :pub-date    :accessor ris-pub-date    :col-default "")
27
+   (source      :col-type text    :initarg :source      :accessor ris-source      :col-default "")
28
+   (feed        :col-type integer :initarg :feed        :accessor ris-feed))
29
+  (:metaclass postmodern:dao-class)
30
+  (:keys id))
31
+
32
+(postmodern:deftable rss-item-store
33
+  (postmodern:!dao-def)
34
+  (postmodern:!foreign "rssfeed" "feed" "id" :on-delete :cascade :on-update :cascade))
35
+
36
+
37
+; (postmodern:create-table 'rss-item-store)
38
+
39
+(defclass user ()
40
+  ((id)
41
+   (foreign-id)
42
+   (email)
43
+   (first-name)
44
+   (gender)
45
+   (last-name)
46
+   (link)
47
+   (locale)
48
+   
49
+   )
50
+  )