Overview
Comment: | Add keyword index page, make index links bidirectional (addresses [5daecde7]) |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
ae6010c03735fca282826d874a0b3f68 |
User & Date: | joel on 2019-05-15 01:13:16 |
Other Links: | manifest | tags |
Context
2019-05-19
| ||
22:11 | Merge license changes check-in: bfde8715 user: joel tags: trunk | |
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-05-10
| ||
12:40 | Mockup → prototype! check-in: 6034ec3d user: joel tags: trunk | |
Changes
Modified crystalize.rkt from [17c941d5] to [e8e2afa2].
︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 58 59 60 61 62 | article-plain-title list/articles list/articles+notes listing<>-short/articles listing<>-full/articles listing<>-full/articles+notes unfence 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 | > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 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 |
︙ | ︙ | |||
145 146 147 148 149 150 151 | [title-plain (tx-strs title-tx)] [series-node (series-pagenode)] [header (html$-article-open pagenode title-specified? title-tx pubdate)] [footertext (make-article-footertext pagenode series-node disposition disp-note-id (length note-txprs))] [footer (html$-article-close footertext)] [notes-section-html (crystalize-notes! pagenode title-plain note-txprs)]) | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | [title-plain (tx-strs title-tx)] [series-node (series-pagenode)] [header (html$-article-open pagenode title-specified? title-tx pubdate)] [footertext (make-article-footertext pagenode series-node disposition disp-note-id (length note-txprs))] [footer (html$-article-close footertext)] [notes-section-html (crystalize-notes! pagenode title-plain note-txprs)]) (crystalize-index-entries! pagenode doc) ; Note the original doc is used here ;; Values must come in the order defined in table_article_fields (define article-record (list (symbol->string pagenode) title-plain title-html (bool->int title-specified?) |
︙ | ︙ |
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 [62911e27] to [5a376d4e].
︙ | ︙ | |||
21 22 23 24 25 26 27 | 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. | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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/ |
︙ | ︙ | |||
45 46 47 48 49 50 51 | 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 $@ | | > > > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 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) |
︙ | ︙ |
Modified tags-html.rkt from [5a9bf33f] to [43d9d1e5].
︙ | ︙ | |||
116 117 118 119 120 121 122 123 124 125 126 127 128 129 | (define file (or (assoc 'filename attrs) "")) (define codeblock `(pre [[class "code"]] (code ,@elems))) (cond [(string>? file "") `(@ (div [[class "listing-filename"]] 128196 " " ,file) ,codeblock)] [else codeblock])) (define (html-index . elems) `(a [[id ,(here-id (list "_idx-" (uri-encode (car elems))))] [data-index-entry ,(car elems)] [class "index-link"]] ,@(cdr elems))) (define (html-say . elems) `(@ (dt ,(car elems) (span [[class "x"]] ": ")) (dd ,@(cdr elems)))) | > | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | (define file (or (assoc 'filename attrs) "")) (define codeblock `(pre [[class "code"]] (code ,@elems))) (cond [(string>? file "") `(@ (div [[class "listing-filename"]] 128196 " " ,file) ,codeblock)] [else codeblock])) (define (html-index . elems) `(a [[id ,(here-id (list "_idx-" (uri-encode (car elems))))] [href ,(string-append "/keyword-index.html#" (uri-encode (string-downcase (car elems))))] [data-index-entry ,(car elems)] [class "index-link"]] ,@(cdr elems))) (define (html-say . elems) `(@ (dt ,(car elems) (span [[class "x"]] ": ")) (dd ,@(cdr elems)))) |
︙ | ︙ |
Modified web-extra/martin.css.pp from [48a09b2d] to [96d16067].
︙ | ︙ | |||
185 186 187 188 189 190 191 | color: inherit; } span.links-footnote { display: inline-block; /* allows keyframe animation to work */ } | | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | color: inherit; } span.links-footnote { display: inline-block; /* allows keyframe animation to work */ } :target { animation: hilite 2.5s; } @keyframes hilite { 0% {background: transparent;} 10% {background: #feffc1;} 100% {background: transparent;} } |
︙ | ︙ | |||
638 639 640 641 642 643 644 645 646 647 648 649 650 651 | div.article-list-date { color: #999; } div.article-list-title { font-size: 1.2rem; } /* 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. */ | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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. */ |
︙ | ︙ |