Comment: | Merge updates from trunk |
---|---|
Timelines: | family | ancestors | descendants | both | licensing |
Files: | files | file ages | folders |
SHA3-256: |
cf26929b73bb95cded78c3b0b3d4f921 |
User & Date: | joel on 2019-05-19 20:24:06 |
Other Links: | branch diff | manifest | tags |
2019-05-19
| ||
21:50 | Switch all license notices to Blue Oak Leaf check-in: 8db9bae9 user: joel tags: licensing | |
20:24 | Merge updates from trunk check-in: cf26929b user: joel tags: licensing | |
2019-05-15
| ||
01:13 | Add keyword index page, make index links bidirectional (addresses [5daecde7]) check-in: ae6010c0 user: joel tags: trunk | |
2019-04-04
| ||
16:12 | Edits to proposed license check-in: 804afbb2 user: joel tags: licensing | |
Modified .fossil-settings/ignore-glob from [9123c029] to [2a3c277b].
11 12 13 14 15 16 17 | 11 12 13 14 15 16 17 18 | - + | *.html *.out *.ltx *.aux *.log *.xml *.toc |
Modified LICENSE.md from [7f1785f5] to [37f6caff].
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | - - - + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + - + + + + + + + + - + + - + - - - - - - - - - - - - - - - - - - - - + - - - - + + + |
|
Added blog.rkt version [44d9d7ad].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | #lang pollen/mode racket/base ;; Copyright (c) 2019 Joel Dueck. ;; ;; Licensed under the Apache License, Version 2.0 (the "License"); ;; you may not use this file except in compliance with the License. ;; A copy of the License is included with this source code, in the ;; file "LICENSE.txt". ;; You may also obtain a copy of the License at ;; ;; http://www.apache.org/licenses/LICENSE-2.0 ;; ;; Unless required by applicable law or agreed to in writing, software ;; distributed under the License is distributed on an "AS IS" BASIS, ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ;; See the License for the specific language governing permissions and ;; limitations under the License. ;; ;; Author contact information: ;; joel@jdueck.net ;; https://joeldueck.com ;; ------------------------------------------------------------------------- ;; Builds the paginated “blog” HTML files (blog-pg1.html ...) from the SQLite cache ;; The files will be written out every time this module is evaluated! (see end) (require "crystalize.rkt" "snippets-html.rkt" racket/file sugar/list) (provide main) ;; How many items per blog page (define per-page 5) ;; Returns a string containing the entire HTML contents of a given blog page (define (blog-page posts-str pagenum total-pages) (define page-nav (html$-paginate-navlinks pagenum total-pages "blog")) ◊string-append{ <!DOCTYPE html> <html lang="en"> ◊html$-page-head[(format "The Local Yarn: Blog, p. ~a" pagenum)] ◊html$-page-body-open[] <aside><i>Everything, in reverse time order. Well, almost everything.</i></aside> <nav id="top-nav"><ul>◊|page-nav|</ul></nav> ◊posts-str <nav id="bottom-nav"><ul>◊|page-nav|</ul></nav> ◊html$-page-body-close[] </html>}) ;; Grabs all the articles+notes from the cache and writes out all the blog page files (define (build-blog) (spell-of-summoning!) ; Turn on the DB (define articles+notes (slice-at (list/articles+notes 'listing_full_html #:series #f) per-page)) (define pagecount (length articles+notes)) (for ([pagenum (in-range 1 (+ 1 pagecount))] [page (in-list articles+notes)]) (define filename (format "blog-pg~a.html" pagenum)) (displayln (format "Writing: ~a" filename)) (display-to-file (blog-page (apply string-append page) pagenum pagecount) filename #:mode 'text #:exists 'replace))) (define (main) ;; Do it! (build-blog)) |
Modified code-docs/crystalize.scrbl from [c3a0a528] to [4b2805a4].
26 27 28 29 30 31 32 | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | “Crystalizing” is an extra layer in between docs and templates that destructures the doc and stores it in various pieces in a SQLite cache. Individual articles save chunks of rendered HTML to the cache when their individual pages are rendered. The SQLite cache is then referenced by any page that collects multiple articles and notes together. This is much faster than fetching docs and metas through Pollen’s cache and re-converting them to HTML. |
Modified code-docs/dust.scrbl from [d396f326] to [f9a0825d].
35 36 37 38 39 40 41 | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | - - + + - + - - + + + - + + + + - + + + + - - + + + + + + + + | @section{Constants} @defthing[default-authorname string? #:value "Joel Dueck"] Used as the default author name for @code{note}s, and (possibly in the future) for articles generally. |
152 153 154 155 156 157 158 159 160 161 162 163 164 165 | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | + + + + + + + + + + + + + + | If @code{(current-metas)} has the key @racket['series], and if the corresponding series defines a meta value for @racket['noun-singular], then return it, otherwise return @racket[""]. @defproc[(series-title) string?] If @code{(current-metas)} has the key @racket['series], and if the corresponding series defines a meta value for @racket['title], then return it, otherwise return @racket[""]. @defproc[(invalidate-series) (or/c void? boolean?)] If the current article specifies a @racket['series] meta, and if a corresponding @filepath{.poly.pm} file exists in @racket[series-folder], attempts to “touch” the last-modified timestamp on that file, returning @racket[#t] on success or @racket[#f] on failure. If either precondition is not true, returns @|void-const|. When an article is being rendered, that means the article has changed, and if the article has changed, its series page (if any) should be updated as well. Touching the @filepath{.poly.pm} file for a series page triggers a re-render of that page when running @tt{make web} to rebuild the web content (see @repo-file{makefile}). Only used in one place, @repo-file{tags-html.rkt}. @defproc[(disposition-values [str string?]) any] Given a string @racket[_str], returns two values: the portion of the string coming before the first space, and the rest of the string. @examples[#:eval dust-eval |
Modified code-docs/pollen.scrbl from [ea32843d] to [a48aad25].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | + | #lang scribble/manual @; Copyright (c) 2019 Joel Dueck @; @; Copying and distribution of this file, with or without modification, @; are permitted in any medium without royalty provided the copyright @; notice and this notice are preserved. This file is offered as-is, @; without any warranty. @(require "scribble-helpers.rkt") @(require (for-label "../pollen.rkt" "../dust.rkt" "../crystalize.rkt" racket/base racket/contract racket/string txexpr pollen/tag pollen/setup pollen/core |
110 111 112 113 114 115 116 117 118 119 120 121 122 123 | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | + + + + + + + + | If you just need small caps without affecting the paragraph, use @code{smallcaps}. @deftogether[(@defproc[(section [element xexpr?] ...) txexpr?] @defproc[(subsection [element xexpr?] ...) txexpr?])] Create second- and third-level headings, respectively. This is counting the article's title as the first-level header (even if the current article has no title). @defproc[(block [element xexpr?] ...) txexpr?] A container for content that should appear grouped together on larger displays. Intended for use in Series pages, where the template is very minimal. You would want output from @racket[listing<>-short/articles] to appear inside a @racket[block], but you would want output from @racket[listing<>-full/articles] to appear outside it (since each article effectively supplies its own block). Only relevant to HTML output. @deftogether[(@defproc[(link [link-id stringish?] [link-text xexpr?]) txexpr?] @defproc[(url [link-id stringish?] [url string?]) void?])] All hyperlinks are specified reference-style. So, to link some text, use the @code{link} tag with an identifier, which can be a string, symbol or number. Elsewhere in the text, use @code{url} with the same identifier to specify the URL: |
152 153 154 155 156 157 158 159 160 161 162 163 164 165 | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | You can refer to a given footnote definition more than once. The @code{fndef} for a given id may be placed anywhere in the source document, even before it is referenced. If you create a @code{fn} reference without a corresponding @code{fndef}, a @code{"Missing footnote definition!"} message will be substituted for the footnote text. Conversely, creating a @code{fndef} that is never referenced will produce no output, warning or error. @deftogether[(@defproc[(dialogue [elements xexpr?] ...) txexpr?] @defproc[(say [interlocutor string?] [elements xexpr?] ...) txexpr?])] Use these two tags together for transcripts of dialogue, chats, screenplays, interviews and so forth. Example usage: @codeblock|{ #lang pollen ◊dialogue{ ◊say["Tavi"]{You also write fiction, or you used to. Do you still?} ◊say["Lorde"]{The thing is, when I write now, it comes out as songs.} } }| @defproc[(index [heading string?] [elements xexpr?] ...) txexpr?] Creates an entry in the keyword index under @racket[_heading] that points back to this spot in the document. If @racket[_elements] is not empty, the web edition of the document will use it as the contents of an understated hyperlink to back to @racket[_heading] in the keyword index. The example below will create two index entries, one under the heading “compassion” and one under the heading “cats”: @codeblock|{ #lang pollen “I have a theory which I suspect is rather immoral,” Smiley went on, more lightly. “Each of us has only a quantum of ◊index["compassion"]{compassion}. That if we lavish our concern on every stray ◊index["cats"] cat we never get to the centre of things. What do you think of it?” }| @defproc[(note [#:date date-str non-empty-string?] [#:author author string? ""] [#:author-url author-url string? ""] [#:disposition disp-str string? ""]) txexpr?] Add a note to the “Further Notes” section of the article. Notes are like blog comments but are |
Modified code-docs/scribble-helpers.rkt from [1eef327e] to [73316e54].
27 28 29 30 31 32 33 | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | - + + + - - + + + + + + + + + | scribble/manual/lang scribble/html-properties (only-in net/uri-codec uri-encode)) (provide (all-defined-out)) (define repo-url/ "https://thelocalyarn.com/cgi-bin/yarncode/") |
Modified code-docs/snippets-html.scrbl from [d3b4b700] to [80a0bc1d].
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | + | "../dust.rkt" "../snippets-html.rkt" racket/base racket/contract racket/string pollen/template pollen/pagetree txexpr sugar/coerce)) @title{@filepath{snippets-html.rkt}} @defmodule["snippets-html.rkt" #:packages ()] Each “snippet” module provides all the document- and article-level blocks of structural markup |
53 54 55 56 57 58 59 | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | - + + + + - - + + + + + + + + + + + | @section{HTML Snippet functions} @defproc[(html$-page-head [title (or/c string? #f) #f]) non-empty-string?] Returns the @tt{<head>} section of an HTML document. |
116 117 118 119 120 121 122 123 | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | + + + + + + + + + | Like @racket[html$-note-listing-full], but returns HTML for a @racket[note] suitable for display inside its parent article. @defproc[(html$-notes-section [note-htmls string?]) non-empty-string?] Returns the complete HTML for the @italic{Further Notes} section of an article. @defproc[(html$-paginate-navlinks [current-page exact-positive-integer?] [pagecount exact-positive-integer?] [basename string?]) string?] On the “blog”, the articles are split across multiple files: @filepath{blog-pg1.html}, @filepath{blog-pg2.html}, etc. This function provides a string containing HTML for a group of links that can be given within each file, to link to the pages that come before/after it. The links are enclosed within @tt{<li>} tags. It’s up to the calling site to provide the enclosing @tt{<ul>} tag (in case any custom styling or IDs need to be applied). |
Modified crystalize.rkt from [87ac52b6] to [e8e2afa2].
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | + + + + + + + + | ;; since the database is merely a disposable cache, and since all the input ;; will be coming from me. (require pollen/setup pollen/core pollen/template racket/string racket/function txexpr db/base "sqlite-tools.rkt" "snippets-html.rkt" "dust.rkt") ;; ~~~ Provides ~~~ (provide spell-of-summoning! crystalize-article! article-plain-title list/articles list/articles+notes listing<>-short/articles listing<>-full/articles listing<>-full/articles+notes unfence sqltools:dbc preheat-series!) ;; ~~~ Private use ~~~ (define DBFILE (build-path (current-project-root) "vitreous.sqlite")) ;; Since the DB exists to serve as a high-speed cache, the tables are constructed so that |
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | + + + + + + + + + + - + - + - + - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | note_id title_html_flow author author_url date disposition content_html series_pagenode listing_full_html listing_excerpt_html ; Not used for now listing_short_html)) (define table_series-fields '(pagenode title published noun_plural noun_singular)) (define table_keywordindex-fields '(entry subentry pagenode anchor)) (define table_articles (make-table-schema "articles" table_articles-fields)) (define table_notes (make-table-schema "notes" table_notes-fields #:primary-key-cols '(pagenode note_id))) (define table_series (make-table-schema "series" table_series-fields)) (define table_keywordindex (make-table-schema "keywordindex" table_keywordindex-fields #:primary-key-cols '(pagenode anchor))) ;; ~~~ Provided functions: Initializing; Saving posts and notes ;; Initialize the database connection, creating the database if it doesn’t ;; exist, and executing the table schema queries ;; (define (spell-of-summoning!) |
175 176 177 178 179 180 181 | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | - + | ;; Convert a bunch of information about an article into some nice English and links. (define (make-article-footertext pagenode series disposition disp-note-id note-count) (define s-title (series-title)) (define s-noun (series-noun)) (define series-part (cond [(non-empty-string? s-title) |
198 199 200 201 202 203 204 | 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | - - + + | pagenode note-count)] [(and (note-count . > . 0) (string=? disposition "")) (format "There is <a href=\"/~a#furthernotes\">a note</a> appended." pagenode)] [else ""])) |
236 237 238 239 240 241 242 | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | - + - + + + + + + + + + + + + + + + + + + + + + + + + | (and ((length (string-split disposition-attr)) . >= . 2))) (raise-arguments-error 'note "must be in format \"[symbol] [past-tense-verb]\"" "disposition attr" disposition-attr)) ;; Parse out remaining columns |
Modified dust.rkt from [43f7824f] to [9569787a].
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | + + + + + - + - - + + - - + + - + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - | ;; joel@jdueck.net ;; https://joeldueck.com ;; ------------------------------------------------------------------------- (require pollen/core pollen/pagetree pollen/setup pollen/file net/uri-codec file/sha1 gregor txexpr racket/list racket/system racket/string) ;; Provides common helper functions used throughout the project (provide maybe-meta ; Select from (current-metas) or default value ("") if not available maybe-attr ; Return an attribute’s value or a default ("") if not available here-output-path here-id series-noun ; Retrieve noun-singular from current 'series meta, or "" series-title ; Retrieve title of series in current 'series meta, or "" series-pagenode |
130 131 132 133 134 135 136 | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | - - | (define test-attrs '([name "Hazel"] [rank "Chief"])) (parameterize ([current-metas test-metas]) (check-equal? (maybe-meta 'name) "Fiver") ; present meta (check-equal? (maybe-meta 'age) "") ; missing meta (check-equal? (maybe-meta 'age 2) 2)) ; alternate default value |
221 222 223 224 225 226 227 | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | - + | (define (build-note-id txpr) (string-append (maybe-attr 'date (get-attrs txpr)) "_" (uri-encode (maybe-attr 'author (get-attrs txpr) default-authorname)))) ;; Extract the last disposition (if any), and the ID of the disposing note, out of a list of notes (define (notes->last-disposition-values txprs) |
Added keyword-index.rkt version [9aa8d227].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | #lang pollen/mode racket/base ;; Copyright (c) 2019 Joel Dueck. ;; ;; Licensed under the Apache License, Version 2.0 (the "License"); ;; you may not use this file except in compliance with the License. ;; A copy of the License is included with this source code, in the ;; file "LICENSE.txt". ;; You may also obtain a copy of the License at ;; ;; http://www.apache.org/licenses/LICENSE-2.0 ;; ;; Unless required by applicable law or agreed to in writing, software ;; distributed under the License is distributed on an "AS IS" BASIS, ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ;; See the License for the specific language governing permissions and ;; limitations under the License. ;; ;; Author contact information: ;; joel@jdueck.net ;; https://joeldueck.com ;; ------------------------------------------------------------------------- ;; Builds an HTML page containing the keyword index for all ◊index entries in ;; the articles, by pulling them out of the SQLite cache DB. (require racket/match racket/list racket/file db/base net/uri-codec pollen/template) (require "crystalize.rkt" "snippets-html.rkt") (provide main) ;; Get the index entries from the SQLite cache, return them as a list of vectors (define (fetch-entries) (define q ◊string-append{ SELECT entry, subentry, a.rowid, "/" || k.pagenode || "#" || anchor AS href, title_plain FROM keywordindex k INNER JOIN articles a ON a.pagenode = k.pagenode ORDER BY entry COLLATE NOCASE ASC;}) (query-rows (sqltools:dbc) q)) ;; Convert a vector (row) into a txexpr representing a link to the original article (define (make-link row) `(a [[href ,(vector-ref row 3)] [title ,(vector-ref row 4)]] ,(number->string (vector-ref row 2)))) ;(require sugar/debug) ;; Convert a list of vectors from the cache DB into a list of the form: ;; (list (cons FIRST-LETTER ;; (list (cons KEYWORD ;; (list LINKS ...)) ;; ...)) ;; ...) (define (group-entries data) (define collated-list (for/fold ([entry-table null] #:result (reverse entry-table)) ([row (in-list data)]) (define this-entry (vector-ref row 0)) (cond [(and (not (null? entry-table)) (string-ci=? (first (first entry-table)) this-entry)) (match-define (cons (list last-entry last-list) rest-entries) entry-table) (cons `(,last-entry ,(append last-list (list (make-link row)))) rest-entries)] [else (cons `(,this-entry ,(list (make-link row))) entry-table)]))) (define (first-letter entry) (char-upcase (first (string->list (first entry))))) (for/list ([letter-group (in-list (group-by first-letter collated-list))]) (list (first-letter (first letter-group)) letter-group))) (define (entry+links->txexpr entry) (match-define (list entry-word links) entry) `(li [[id ,(uri-encode (string-downcase entry-word))]] ,entry-word nbsp ,@(add-between links ", "))) ;; Return the complete HTML for the keyword index. Each letter group begins with a heading for the ;; letter, followed by a definition list for its entries. (define (html$-index entries) (define groups (for/list ([letter-group (in-list entries)]) (match-define (list letter-char entries) letter-group) `(section (h2 ,(list->string (list letter-char))) (ul ,@(map entry+links->txexpr entries))))) (apply string-append (map ->html groups))) (define (html$-keywordindex-page the-index) ◊string-append{ <!DOCTYPE html> <html lang="en"> ◊html$-page-head{The Local Yarn: Keyword Index} ◊html$-page-body-open[] <div id="keywordindex"> ◊the-index </div> ◊html$-page-body-close[] </html>}) (define (main) (spell-of-summoning!) ; Turn on DB (displayln "Writing keyword-index.html…") (display-to-file (html$-keywordindex-page (html$-index (group-entries (fetch-entries)))) "keyword-index.html" #:mode 'text #:exists 'replace)) |
Modified makefile from [162f37c8] to [dd1c5378].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + | # Licensed under the terms of the Blue Oak Model License 1.0.0 # https://blueoakcouncil.org/license/1.0.0 # You may not use this file except in compliance with that license. SHELL = /bin/bash # ~~~ Variables used by rules ~~~ # core-files := pollen.rkt dust.rkt html-deps := snippets-html.rkt tags-html.rkt article-sources := $(wildcard articles/*.poly.pm) articles-html := $(patsubst %.poly.pm, %.html, $(article-sources)) articles-pdf := $(patsubst %.poly.pm, %.pdf, $(article-sources)) series-sources := $(wildcard series/*.poly.pm) series-html := $(patsubst %.poly.pm, %.html, $(series-sources)) # ~~~ Rules ~~ # # The order of these dependencies is important. They will be processed left to right. web: _article_htmls.mark $(articles-html) $(series-html) blog-pg1.html keyword-index.html web: ## Rebuild all web content (not PDFs) # The file article_htmls.mark is a zero-byte file that serves only as a marker. If it is older than # any of its dependencies (or missing) all of the articles will be rebuilt. Its dependencies are # also on the Pollen cache watchlist (see pollen.rkt) _article_htmls.mark: $(core-files) $(html-deps) template.html.p raco pollen setup articles/ raco pollen render -p -t html articles/*.poly.pm raco pollen setup series/ raco pollen render -p -t html series/*.poly.pm touch _article_htmls.mark # If the rule for article_htmls.mark was triggered, all the article HTML files will already have # been re-rendered. (That rule comes before this one in the list of dependencies for "all") But if # not, any individual files that have been edited will get re-rendered. $(articles-html): %.html: %.poly.pm raco pollen render $@ # Note that if any article is part of a series, it will touch its series .poly.pm file during its # render, triggering this rule for that series. $(series-html): %.html: %.poly.pm raco pollen render $@ # This target will also rebuild pg2, pg3, etc. as needed blog-pg1.html: $(core-files) $(html-deps) $(articles-html) blog.rkt rm -f blog*.html racket -tm blog.rkt keyword-index.html: $(core-files) $(html-deps) $(articles-html) keyword-index.rkt racket -tm keyword-index.rkt spritz: ## Clear Pollen and Scribble cache rm -rf compiled code-docs/compiled articles/compiled series/compiled fossil clean code-docs/ publish: check-env publish: ## Sync all HTML and PDF stuff to the public web server (does not rebuild any files) raco pollen publish ./util/relativize ~/Desktop/publish/ rsync -av ~/Desktop/publish/ -e 'ssh -p $(WEB_SRV_PORT)' $(LOCALYARN_SRV) \ --delete \ --exclude=drafts \ --exclude=code-docs \ --exclude=util \ --exclude=x-mockup \ --exclude=repo-www \ --exclude=scribbled \ --exclude='*.sqlite' \ --exclude='*.fossil' \ --exclude=.fossil-settings \ --exclude=.fslckout \ --exclude='*.ltx' \ --exclude='*.swp' \ --exclude='*.mark' \ --exclude=.DS_Store \ --exclude='template*.*' \ --exclude=makefile rm -rf ~/Desktop/publish scribble: ## Rebuild code documentation and update Fossil repo scribble --htmls +m --redirect https://docs.racket-lang.org/local-redirect/ code-docs/main.scrbl fossil uv rm scribbled/* rm -rf scribbled/* mv main/* scribbled/ cp code-docs/scribble-iframe.html scribbled/scribble.html rm -rf main fossil uv add scribbled/* fossil uv sync # Self-documenting makefile (http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html) help: ## Displays this help screen @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' article: ## Start a new article from a template racket -tm util/newpost.rkt |
Modified pollen.rkt from [08620f02] to [a9e6e1d2].
23 24 25 26 27 28 29 | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | - + + + - + + + + + + - - - - + + + + + + + + | "snippets-html.rkt" "crystalize.rkt") (provide (all-defined-out) (all-from-out "crystalize.rkt" "snippets-html.rkt")) (module setup racket/base |
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | + + + + | (poly-branch-tag blockquote) (poly-branch-tag newthought) (poly-branch-tag smallcaps) (poly-branch-tag center) (poly-branch-tag section) (poly-branch-tag subsection) (poly-branch-tag code) (poly-branch-tag dialogue) (poly-branch-tag say) (poly-branch-tag index) (poly-branch-kwargs-tag blockcode) (poly-branch-kwargs-tag verse) ; [#:title ""] [#:italic "no"] (poly-branch-tag link) (poly-branch-tag url) (poly-branch-tag fn) (poly-branch-tag fndef) (poly-branch-kwargs-tag note) (poly-branch-tag block) ;; Not yet implemented ; (poly-branch-tag table) ; #:columns "" ; (poly-branch-tag inline-math) ; (poly-branch-tag margin-note) ; (poly-branch-tag noun) ; (poly-branch-func index-entry entry) |
Modified repo-www/home.wiki from [c5c5a67b] to [1176a2aa].
1 2 3 4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | - - + + - - + - - - - - + + + + | <title>Hello</title> <img src="/doc/ckout/repo-www/flammarion.jpg" style="--imgwidth:372px" class="spot-image"> |
Added series/template.html.p version [2bb23760].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | + + + + + + + + + + + + + + | <!DOCTYPE html> <html lang="en"> ◊html$-page-head[(select-from-metas 'title metas)] ◊html$-page-body-open["series-page"] ◊(unfence (->html doc #:splice? #t)) ◊html$-page-body-close[] </html> |
Modified snippets-html.rkt from [fd84a05e] to [55ae0657].
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | + + + - + + - - + + + - + - + - + - + - + + + + + + + + - + - - - - - - - - - + + + - - - + + - + - - - + + + | ;; ------------------------------------------------------------------------- ;; Provides functions for displaying content in HTML templates. (require pollen/core pollen/template pollen/decode racket/string racket/function racket/list txexpr openssl/sha1 "dust.rkt") (provide html$-page-head html$-page-body-open html$-article-open html$-article-close html$-article-listing-short html$-page-body-close html$-note-title html$-note-contents html$-note-listing-full html$-note-in-article |
155 156 157 158 159 160 161 | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | </div>}) (define (html$-notes-section note-htmls) ◊string-append{<div class="further-notes" id="furthernotes"> <h2>Further Notes</h2> ◊(apply string-append note-htmls) </div>}) ;; (private) Returns HTML for a list-item link to a particular page in a set of numbered pages (define (html$-paginate-link basename pagenum [linktext (number->string pagenum)] [class ""]) (define cstr (if (non-empty-string? class) (format " class=\"~a\"" class) "")) (format "<li~a><a href=\"/~a-pg~a.html\">~a</a></li>" cstr basename pagenum linktext)) ;; Returns HTML for a series of list items with links to numbered pages (define (html$-paginate-navlinks pagenum pagecount basename) (define slots 9) (define on-first-group? (<= pagenum (- slots 4))) (define on-last-group? (>= pagenum (- pagecount slots -4))) (define only-one-group? (<= pagecount slots)) (define group-start (- pagenum (quotient (- slots 4) 2))) ; not always used! (define page-func (curry html$-paginate-link basename)) (define page-group-syms (cond [only-one-group? `(,@(range 1 (+ 1 pagecount)))] [on-first-group? `(,@(range 1 (min (+ 1 pagecount) (- slots 1))) "..." ,pagecount)] [on-last-group? `(1 "..." ,@(range (- pagecount slots -3) (+ pagecount 1)))] [else `(1 "..." ,@(range group-start (min (+ 1 pagecount) (+ group-start (- slots 4)))) "..." ,pagecount)])) (define page-group (for/list ([psym (in-list page-group-syms)]) (cond [(and (number? psym) (equal? psym pagenum)) (format "<li class=\"current-page\">~a</li>" psym)] [(number? psym) (page-func psym)] [else "<li>…</li>"]))) (define prev-link (if (eq? 1 pagenum) "<li class=\"nav-text inactive-link\">←Newer</li>" (page-func (- pagenum 1) "← Newer" "nav-text"))) (define next-link (if (eq? pagecount pagenum) "<li class=\"nav-text inactive-link\">Older→</li>" (page-func (+ pagenum 1) "Older →" "nav-text"))) (string-join `(,prev-link ,@page-group ,next-link))) |
Modified tags-html.rkt from [a6c4e837] to [43d9d1e5].
24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | + | ;; Tag functions used by pollen.rkt when HTML is the output format. (require (for-syntax racket/base racket/syntax)) (require racket/list racket/function pollen/decode pollen/tag net/uri-codec txexpr "dust.rkt") (provide html-fn html-fndef) ;; Customized paragraph decoder replaces single newlines within paragraphs |
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | + + + + + + + + + - + - + + + + + + + + + + + - + - + - + | (provide html-root html-item html-section html-subsection html-newthought html-smallcaps html-center html-block html-blockcode html-index html-dialogue html-say html-verse html-link html-url html-fn html-fndef html-note) (define html-item (default-tag-function 'li)) (define html-section (default-tag-function 'h2)) (define html-subsection (default-tag-function 'h3)) (define html-newthought (default-tag-function 'span #:class "newthought")) (define html-smallcaps (default-tag-function 'span #:class "smallcaps")) (define html-center (default-tag-function 'div #:style "text-align: center")) (define html-dialogue (default-tag-function 'dl #:class "dialogue")) (define (html-block . elements) `(section [[class "content-block"]] (div [[class "content-block-main"]] ,@elements))) (define (html-root . elements) (invalidate-series) (define first-pass |
188 189 190 191 192 193 194 | 208 209 210 211 212 213 214 215 | - + | (fn-id fn-name) (format "~a" (+ 1 fnref-num)))]] "↩"))]) `(li [[id ,(fndef-id fn-name)]] ,@definition-text ,@backrefs)))) (cond [(null? note-items) ""] [else `(section ((class "footnotes")) (hr) (ol ,@note-items))])) (define (html-note attrs elems) |
Modified template.html.p from [406d1c49] to [51a5e67e].
1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | - + - | <!DOCTYPE html> |
Added util/newpost.rkt version [88a7503d].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | #lang pollen/mode racket/base ;; Copyright (c) 2018 Joel Dueck. ;; ;; Licensed under the Apache License, Version 2.0 (the "License"); ;; you may not use this file except in compliance with the License. ;; A copy of the License is included with this source code, in the ;; file "LICENSE.txt". ;; You may also obtain a copy of the License at ;; ;; http://www.apache.org/licenses/LICENSE-2.0 ;; ;; Unless required by applicable law or agreed to in writing, software ;; distributed under the License is distributed on an "AS IS" BASIS, ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ;; See the License for the specific language governing permissions and ;; limitations under the License. ;; ;; Author contact information: ;; joel@jdueck.net ;; https://joeldueck.com ;; ------------------------------------------------------------------------- (require racket/date racket/string racket/file racket/system "../dust.rkt") (provide main) (define (normalize str) (define alphanum-only (regexp-replace* #rx"[^A-Za-z0-9 ]" str "")) (string-normalize-spaces (string-downcase alphanum-only) #px"\\s+" "-")) (define (make-filename basename) (build-path (current-directory) articles-folder (string-append basename ".poly.pm"))) (define (comment . strs) (format "◊; ~a" (apply string-append strs))) (define date-string (parameterize [(date-display-format 'iso-8601)] (date->string (current-date)))) (define (make-template-contents title) ◊string-append{ #lang pollen ◊comment{Copyright ◊(substring date-string 0 4) by ◊|default-authorname|. All Rights Reserved.} ◊"◊"(define-meta published "◊date-string") ◊"◊"(define-meta series "seriesname") ◊"◊"title{◊title} Write here!}) (define (main) (display "Enter title: ") (define title (read-line)) (cond [(non-empty-string? title) (define post-file (make-filename (normalize title))) (define post-contents (make-template-contents title)) (display-to-file post-contents post-file) (displayln (format "Saved to ~a" post-file)) ; the + argument tells vim to place the cursor at the last line of the file. (system (format "mvim + ~a" post-file))])) |
Added util/relativize version [5428bcab].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | #!/bin/bash # Licensed under the terms of the Blue Oak Model License 1.0.0 # https://blueoakcouncil.org/license/1.0.0 # The HTML generated assumes the whole site lives in the domain root. This script converts all links # and image sources to relative URLs, so things don't break when accessed from within a subfolder of # a live web server. (See ‘publish’ target of makefile) # Stop on any error, forbid uninitialized vars set -eu # First parameter is used as working dir, defaults to ./ base_dir=${1:-"./"} # Ensure directory name ends with a slash [[ "${base_dir}" != */ ]] && base_dir="${base_dir}/" # Ensure directory exists if [[ ! -d "${base_dir}" ]]; then echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: ${base_dir} not a directory!" >&2 exit 1 fi # Root folder: remove leading / from href and src attributes sed -i '' -- 's/href=\"\//href=\"/g' "${base_dir}"*.html sed -i '' -- 's/src=\"\//src=\"/g' "${base_dir}"*.html # subfolders: replace leading / with ../ in href and src attributes sed -i '' -- 's/href=\"\//href=\"..\//g' "${base_dir}"articles/*.html sed -i '' -- 's/src=\"\//src=\"..\//g' "${base_dir}"articles/*.html sed -i '' -- 's/href=\"\//href=\"..\//g' "${base_dir}"series/*.html sed -i '' -- 's/src=\"\//src=\"..\//g' "${base_dir}"series/*.html |
Added web-extra/mark.svg version [adb51b3e].
cannot compute difference between binary files
Modified web-extra/martin.css.pp from [cea56616] to [96d16067].
119 120 121 122 123 124 125 | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | - + - - + + + - + + - + - - + + - - - - - + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - + | main { background: white; margin: 0; padding: ◊x-lineheight[0.5] ◊x-lineheight[1]; } |
238 239 240 241 242 243 244 | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | - + | background: none; color: ◊color-bodytext; } a.rel-bookmark:hover, /* Has */ a.rel-bookmark:active { /* Arrived */ text-decoration: none; |
298 299 300 301 302 303 304 305 306 307 308 309 310 311 | 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | + + + + + | font-feature-settings: "smcp" on, "liga" on, "clig" on, "dlig" on, "kern" on, "onum" on, "pnum" on; color: #888; } footer.article-info::before { content: "☞\00a0"; } /* Within article info, don’t display series info when on a series page (redundant) */ body.series-page .series-part { display: none; } p.time::before { content: none; } p.time { font-size: ◊x-lineheight[0.75]; |
420 421 422 423 424 425 426 427 428 429 430 431 432 433 | 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | + + + + + + | margin: ◊x-lineheight[1] auto; display: table; white-space: pre-wrap; /* Whitespace is preserved by the browser. Text will wrap when necessary, and on line breaks */ } p.verse-heading { font-feature-settings: "smcp" on, "liga" on, "clig" on, "dlig" on, "kern" on, "onum" on, "pnum" on; text-align: center; font-size: 1.3rem; } section.entry-content figure { margin: ◊x-lineheight[1] 0; padding: 0; } figure>a { margin: 0; |
523 524 525 526 527 528 529 | 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | - - - - - - - + + - - - - - - - - - - - + | color: ◊color-xrefmark; display: inline-block; width: 1em; } /* ******* (Mobile first) Journal View styling ******* */ |
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 | 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | + + + + + + + + + + + + + + + + + + + + + + + + - + + + - - - - - - - - - - - - - + | div.article-list-date { color: #999; } div.article-list-title { font-size: 1.2rem; } /* ******* (Mobile first) Keyword Index styling ******* */ #keywordindex { column-width: 7rem; margin-top: ◊x-lineheight[2]; } #keywordindex section { -webkit-column-break-inside: avoid; /* Chrome, Safari, Opera */ page-break-inside: avoid; /* Firefox */ break-inside: avoid; /* IE 10+ */ } #keywordindex h2 { margin: 0; } #keywordindex ul { margin-top: 0; list-style-type: none; padding: 0; } /* End of mobile-first typography and layout */ } /* Here’s where we start getting funky for any viewport wider than mobile portrait. An iPhone 6 is 667px wide in landscape mode, so that’s our breakpoint. */ @media only screen and (min-width: 667px) { main { |
665 666 667 668 669 670 671 | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 | + - + - + | font-size: 0.8rem; line-height: ◊derive-lineheight[4 #:per-lines 3]; margin: 0; padding-left: 3px; } article.no-title footer.article-info { margin-top: 1.5rem; |
727 728 729 730 731 732 733 | 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 | - + - + - - + + + + - - - + + + + - - - - - - - + - - + + | div.note h3 { } /* ******* (Grid support) Journal View styling ******* */ |