diff --git a/.gitignore b/.gitignore index 17b94c5..caf5d54 100644 --- a/.gitignore +++ b/.gitignore @@ -10,9 +10,6 @@ # Compiled compiled -/breezewiki -/dist -/breezewiki-dist # Personal /config.ini diff --git a/breezewiki.rkt b/breezewiki.rkt index 22f368c..1f39521 100644 --- a/breezewiki.rkt +++ b/breezewiki.rkt @@ -10,33 +10,23 @@ (prefix-in filter: web-server/dispatchers/dispatch-filter) (prefix-in files: web-server/dispatchers/dispatch-files) "src/config.rkt" - "src/reloadable.rkt" - "src/server-utils.rkt") - -(define-syntax-rule (require-reloadable filename varname) - (define varname - (reloadable-entry-point->procedure - (make-reloadable-entry-point (quote varname) filename)))) - -(require-reloadable "src/page-category.rkt" page-category) -(require-reloadable "src/page-home.rkt" page-home) -(require-reloadable "src/page-not-found.rkt" page-not-found) -(require-reloadable "src/page-proxy.rkt" page-proxy) -(require-reloadable "src/page-search.rkt" page-search) -(require-reloadable "src/page-wiki.rkt" page-wiki) - -(when (not (config-true? 'debug)) - (set-reload-poll-interval! #f)) -(reload!) + "src/page-category.rkt" + "src/page-not-found.rkt" + "src/page-proxy.rkt" + "src/page-wiki.rkt" + "src/page-search.rkt") (define-runtime-path path-static "static") +(define mime-types + (hash #".css" #"text/css" + #".svg" #"image/svg+xml")) + (serve/launch/wait #:listen-ip (if (config-true? 'debug) "127.0.0.1" #f) #:port (string->number (config-get 'port)) (λ (quit) (sequencer:make - (pathprocedure:make "/" page-home) (pathprocedure:make "/proxy" page-proxy) (filter:make #rx"^/[a-z-]+/wiki/Category:.+$" (lift:make page-category)) (filter:make #rx"^/[a-z-]+/wiki/.+$" (lift:make page-wiki)) @@ -48,6 +38,6 @@ (struct-copy url u [path (cdr (url-path u))]))) #:path->mime-type (lambda (u) - (ext->mime-type (path-get-extension u))) + (hash-ref mime-types (path-get-extension u))) #:cache-no-cache (config-true? 'debug) #;"browser applies heuristics if unset")) (lift:make page-not-found)))) diff --git a/dist.rkt b/dist.rkt deleted file mode 100644 index 19fc736..0000000 --- a/dist.rkt +++ /dev/null @@ -1,43 +0,0 @@ -#lang racket/base -(require racket/path - racket/runtime-path - net/url - web-server/servlet-dispatch - web-server/dispatchers/filesystem-map - (prefix-in pathprocedure: web-server/dispatchers/dispatch-pathprocedure) - (prefix-in sequencer: web-server/dispatchers/dispatch-sequencer) - (prefix-in lift: web-server/dispatchers/dispatch-lift) - (prefix-in filter: web-server/dispatchers/dispatch-filter) - (prefix-in files: web-server/dispatchers/dispatch-files) - "src/config.rkt" - "src/server-utils.rkt") - -(require (only-in "src/page-category.rkt" page-category)) -(require (only-in "src/page-home.rkt" page-home)) -(require (only-in "src/page-not-found.rkt" page-not-found)) -(require (only-in "src/page-proxy.rkt" page-proxy)) -(require (only-in "src/page-search.rkt" page-search)) -(require (only-in "src/page-wiki.rkt" page-wiki)) - -(define-runtime-path path-static "static") - -(serve/launch/wait - #:listen-ip (if (config-true? 'debug) "127.0.0.1" #f) - #:port (string->number (config-get 'port)) - (λ (quit) - (sequencer:make - (pathprocedure:make "/" page-home) - (pathprocedure:make "/proxy" page-proxy) - (filter:make #rx"^/[a-z-]+/wiki/Category:.+$" (lift:make page-category)) - (filter:make #rx"^/[a-z-]+/wiki/.+$" (lift:make page-wiki)) - (filter:make #rx"^/[a-z-]+/search$" (lift:make page-search)) - (filter:make #rx"^/static/" (files:make - #:url->path - (lambda (u) - ((make-url->path path-static) - (struct-copy url u [path (cdr (url-path u))]))) - #:path->mime-type - (lambda (u) - (ext->mime-type (path-get-extension u))) - #:cache-no-cache (config-true? 'debug) #;"browser applies heuristics if unset")) - (lift:make page-not-found)))) diff --git a/src/page-home.rkt b/src/page-home.rkt deleted file mode 100644 index c42102e..0000000 --- a/src/page-home.rkt +++ /dev/null @@ -1,77 +0,0 @@ -#lang racket/base - -(require html-writing - web-server/http - "xexpr-utils.rkt" - "config.rkt") - -(provide - page-home) - -(module+ test - (require rackunit)) - -(define examples - '(("crosscode" "CrossCode_Wiki") - ("minecraft" "Bricks") - ("undertale" "Hot_Dog...%3F") - ("tardis" "Eleanor_Blake") - ("fireemblem" "God-Shattering_Star") - ("fallout" "Pip-Boy_3000"))) - -(define content - `((h2 "BreezeWiki makes wiki pages on Fandom readable") - (p "It removes ads, videos, and suggested content, leaving you with a clean page that doesn't consume all your data.") - (p "If you're looking for an \"alternative\" to Fandom for writing pages, you should look elsewhere. BreezeWiki only lets you read existing pages.") - (p "BreezeWiki can also be called an \"alternative frontend for Fandom\".") - (h2 "Example pages") - (ul - ,@(map (λ (x) - `(li (a (@ (href ,(apply format "/~a/wiki/~a" x))) - ,(apply format "~a: ~a" x)))) - examples)) - (h2 "How to use") - (p "While browsing any page on Fandom, you can replace \"fandom.com\" in the address bar with \"breezewiki.com\" to see the BreezeWiki version of that page.") - (p "After that, you can click the links to navigate around the pages.") - (p "To get back to Fandom, click the link that's at the bottom of the page."))) - -(define body - `(html - (head - (meta (@ (name ")viewport") (content "width=device-width, initial-scale=1"))) - (title "About | BreezeWiki") - (link (@ (rel "stylesheet") (type "text/css") (href "/static/internal.css"))) - (link (@ (rel "stylesheet") (type "text/css") (href "/static/main.css")))) - (body (@ (class "skin-fandomdesktop theme-fandomdesktop-light internal")) - (div (@ (class "main-container")) - (div (@ (class "fandom-community-header__background tileBoth header"))) - (div (@ (class "page")) - (main (@ (class "page__main")) - (div (@ (class "custom-top")) - (h1 (@ (class "page-title")) - "About BreezeWiki")) - (div (@ (id "content") #;(class "page-content")) - (div (@ (id "mw-content-text")) - ,@content)) - (footer (@ (class "custom-footer")) - (div (@ (class "internal-footer")) - (img (@ (class "my-logo") (src "/static/breezewiki.svg"))) - ,(if (config-get 'instance-is-official) - `(p ,(format "This instance is run by the ~a developer, " (config-get 'application-name)) - (a (@ (href "https://cadence.moe/contact")) - "Cadence.")) - `(p - ,(format "This unofficial instance is based off the ~a source code, but is not controlled by the code developer." (config-get 'application-name)))) - (p "Text content on wikis run by Fandom is available under the Creative Commons Attribution-Share Alike License 3.0 (Unported), " - (a (@ (href "https://www.fandom.com/licensing")) "see license info.") - " Media files and official Fandom documents have different copying restrictions.") - (p ,(format "Fandom is a trademark of Fandom, Inc. ~a is not affiliated with Fandom." (config-get 'application-name))))))))))) -(module+ test - (check-not-false (xexp->html body))) - -(define (page-home req) - (response/output - #:code 200 - (λ (out) - (write-html body out)))) - diff --git a/src/page-search.rkt b/src/page-search.rkt index 7b0abe3..5948af0 100644 --- a/src/page-search.rkt +++ b/src/page-search.rkt @@ -69,7 +69,7 @@ (define data (easy:response-json dest-res)) (define body (generate-results-page dest-url wikiname query data)) - (when (config-true? 'debug) + (when (config-get 'debug) ; used for its side effects ; convert to string with error checking, error will be raised if xexp is invalid (xexp->html body)) diff --git a/src/page-wiki.rkt b/src/page-wiki.rkt index f070521..abd4aeb 100644 --- a/src/page-wiki.rkt +++ b/src/page-wiki.rkt @@ -168,9 +168,8 @@ (λ (v) (and (has-class? "animated" attributes) ((length v) . > . 1))) (λ (v) - `((span (@ (class "animated-slot__outer") (style ,(format "--steps: ~a" (length v)))) - (span (@ (class "animated-slot__inner")) - ,@v)))))) + `((span (@ (class "animated-slot") (style ,(format "--steps: ~a" (length v)))) + ,@v))))) children))])) tree)) (module+ test diff --git a/src/reloadable.rkt b/src/reloadable.rkt deleted file mode 100644 index 61c93c5..0000000 --- a/src/reloadable.rkt +++ /dev/null @@ -1,150 +0,0 @@ -#lang racket/base - -;;; Source: https://github.com/tonyg/racket-reloadable/blob/master/reloadable/main.rkt -;;; Source commit: cae2a14 from 24 May 2015 -;;; Source license: LGPL 3 or later - -(provide (struct-out reloadable-entry-point) - reload-poll-interval - set-reload-poll-interval! - reload-failure-retry-delay - reload! - make-reloadable-entry-point - lookup-reloadable-entry-point - reloadable-entry-point->procedure - make-persistent-state) - -(require racket/set) -(require racket/string) -(require racket/match) -(require racket/rerequire) - -(define reload-poll-interval 0.5) ;; seconds -(define reload-failure-retry-delay (make-parameter 5)) ;; seconds - -(struct reloadable-entry-point (name - module-path - identifier-symbol - on-absent - [value #:mutable]) - #:prefab) - -(define reloadable-entry-points (make-hash)) -(define persistent-state (make-hash)) - -(define (set-reload-poll-interval! v) - (set! reload-poll-interval v)) - -(define (reloader-main) - (let loop () - (match (sync (handle-evt (thread-receive-evt) - (lambda (_) (thread-receive))) - (if reload-poll-interval - (handle-evt (alarm-evt (+ (current-inexact-milliseconds) - (* reload-poll-interval 1000))) - (lambda (_) (list #f 'reload))) - never-evt)) - [(list ch 'reload) - (define result (do-reload!)) - (when (not result) (sleep (reload-failure-retry-delay))) - (when ch (channel-put ch result))]) - (loop))) - -(define reloader-thread (thread reloader-main)) - -(define (reloader-rpc . request) - (define ch (make-channel)) - (thread-send reloader-thread (cons ch request)) - (channel-get ch)) - -(define (reload!) (reloader-rpc 'reload)) - -(define first-load? #t) -(define (say-loading-once! port) - (when first-load? - (display "loading support files" port) - (set! first-load? #f))) - -(define (handle-loader-output) - (define i (thread-receive)) - (define real-error-port (thread-receive)) - (say-loading-once! real-error-port) - (let loop () - (let ([line (read-line i)]) - (cond - [(eof-object? line) - (void)] - [(string-contains? line "[load") - (display "." real-error-port) - (loop)] - [#t - (displayln line real-error-port) - (loop)])))) - -;; Only to be called from reloader-main -(define (do-reload!) - (define module-paths (for/set ((e (in-hash-values reloadable-entry-points))) - (reloadable-entry-point-module-path e))) - (with-handlers ((exn:fail? - (lambda (e) - (log-error "*** WHILE RELOADING CODE***\n~a" - (parameterize ([current-error-port (open-output-string)]) - ((error-display-handler) (exn-message e) e) - (get-output-string (current-error-port)))) - #f))) - (for ((module-path (in-set module-paths))) - (let ([real-error-port (current-error-port)]) - (define-values (i o) (make-pipe)) - (parameterize ([current-error-port o]) - (define new-thread (thread handle-loader-output)) - (thread-send new-thread i) - (thread-send new-thread real-error-port) - (dynamic-rerequire module-path #:verbosity 'all)))) - (for ((e (in-hash-values reloadable-entry-points))) - (match-define (reloadable-entry-point _ module-path identifier-symbol on-absent _) e) - (define new-value (if on-absent - (dynamic-require module-path identifier-symbol on-absent) - (dynamic-require module-path identifier-symbol))) - (set-reloadable-entry-point-value! e new-value)) - #t)) - -(define (make-reloadable-entry-point name module-path [identifier-symbol name] - #:on-absent [on-absent #f]) - (define key (list module-path name)) - (hash-ref reloadable-entry-points - key - (lambda () - (define e (reloadable-entry-point name module-path identifier-symbol on-absent #f)) - (hash-set! reloadable-entry-points key e) - e))) - -(define (lookup-reloadable-entry-point name module-path) - (hash-ref reloadable-entry-points - (list module-path name) - (lambda () - (error 'lookup-reloadable-entry-point - "Reloadable-entry-point ~a not found in module ~a" - name - module-path)))) - -(define (reloadable-entry-point->procedure e) - (make-keyword-procedure - (lambda (keywords keyword-values . positionals) - (keyword-apply (reloadable-entry-point-value e) - keywords - keyword-values - positionals)))) - -(define (make-persistent-state name initial-value-thunk) - (hash-ref persistent-state - name - (lambda () - (define value (initial-value-thunk)) - (define handler - (case-lambda - [() value] - [(new-value) - (set! value new-value) - value])) - (hash-set! persistent-state name handler) - handler))) diff --git a/src/server-utils.rkt b/src/server-utils.rkt deleted file mode 100644 index f41c2e6..0000000 --- a/src/server-utils.rkt +++ /dev/null @@ -1,16 +0,0 @@ -#lang racket/base - -(provide - ext->mime-type) - -(module+ test - (require rackunit)) - -(define hash-ext-mime-type - (hash #".css" #"text/css" - #".svg" #"image/svg+xml" - #".png" #"image/png")) -(define (ext->mime-type ext) - (hash-ref hash-ext-mime-type ext)) -(module+ test - (check-equal? (ext->mime-type #".png") #"image/png")) diff --git a/src/xexpr-utils.rkt b/src/xexpr-utils.rkt index b2b4422..a6bf1ca 100644 --- a/src/xexpr-utils.rkt +++ b/src/xexpr-utils.rkt @@ -195,7 +195,6 @@ #:mime-type #"text/plain" (λ (out) (for ([port (list (current-output-port) out)]) - (parameterize ([current-error-port out]) - (displayln "Exception raised in Racket code at response generation time:" (current-error-port)) - ((error-display-handler) (exn-message e) e))))))]) + (displayln "Exception raised in Racket code at response generation time:" port) + (displayln (exn-message e) port)))))]) body ...)) diff --git a/static/internal-background.png b/static/internal-background.png deleted file mode 100644 index db9e066..0000000 Binary files a/static/internal-background.png and /dev/null differ diff --git a/static/internal.css b/static/internal.css deleted file mode 100644 index 6cc9294..0000000 --- a/static/internal.css +++ /dev/null @@ -1,173 +0,0 @@ -:root { - --theme-body-dynamic-color-1: #fff; - --theme-body-dynamic-color-1--rgb: 255,255,255; - --theme-body-dynamic-color-2: #e6e6e6; - --theme-body-dynamic-color-2--rgb: 230,230,230; - --theme-page-dynamic-color-1: #000; - --theme-page-dynamic-color-1--rgb: 0,0,0; - --theme-page-dynamic-color-1--inverted: #fff; - --theme-page-dynamic-color-1--inverted--rgb: 255,255,255; - --theme-page-dynamic-color-2: #3a3a3a; - --theme-page-dynamic-color-2--rgb: 58,58,58; - --theme-sticky-nav-dynamic-color-1: #000; - --theme-sticky-nav-dynamic-color-1--rgb: 0,0,0; - --theme-sticky-nav-dynamic-color-2: #3a3a3a; - --theme-sticky-nav-dynamic-color-2--rgb: 58,58,58; - --theme-link-dynamic-color-1: #000; - --theme-link-dynamic-color-1--rgb: 0,0,0; - --theme-link-dynamic-color-2: #3a3a3a; - --theme-link-dynamic-color-2--rgb: 58,58,58; - --theme-accent-dynamic-color-1: #fff; - --theme-accent-dynamic-color-1--rgb: 255,255,255; - --theme-accent-dynamic-color-2: #e6e6e6; - --theme-accent-dynamic-color-2--rgb: 230,230,230; - --theme-body-background-color: #286cab; - --theme-body-background-color--rgb: 40,108,171; - - --theme-body-text-color: #fff; - --theme-body-text-color--rgb: 255,255,255; - --theme-body-text-color--hover: #cccccc; - --theme-sticky-nav-background-color: #ffffff; - --theme-sticky-nav-background-color--rgb: 255,255,255; - --theme-sticky-nav-text-color: #000; - --theme-sticky-nav-text-color--hover: #333333; - --theme-page-background-color: #ffffff; - --theme-page-background-color--rgb: 255,255,255; - --theme-page-background-color--secondary: #f2f2f2; - --theme-page-background-color--secondary--rgb: 242,242,242; - --theme-page-text-color: #3a3a3a; - --theme-page-text-color--rgb: 58,58,58; - --theme-page-text-color--hover: #6d6d6d; - --theme-page-text-mix-color: #9d9d9d; - --theme-page-text-mix-color-95: #f5f5f5; - --theme-page-accent-mix-color: #b6b6b6; - --theme-page-headings-font: 'Rubik'; - --theme-link-color: #8a8a8a; - --theme-link-color--rgb: 138,138,138; - --theme-link-color--hover: #565656; - --theme-link-label-color: #000; - --theme-accent-color: #6c6c6c; - --theme-accent-color--rgb: 108,108,108; - --theme-accent-color--hover: #9f9f9f; - --theme-accent-label-color: #fff; - --theme-border-color: #cecece; - --theme-border-color--rgb: 206,206,206; - --theme-alert-color: #bf0017; - --theme-alert-color--rgb: 191,0,23; - --theme-alert-color--hover: #59000a; - --theme-alert-color--secondary: #bf0017; - --theme-alert-label: #fff; - --theme-warning-color: #cf721c; - --theme-warning-color--rgb: 207,114,28; - --theme-warning-color--secondary: #ce711b; - --theme-warning-label: #000; - --theme-success-color: #0c742f; - --theme-success-color--rgb: 12,116,47; - --theme-success-color--secondary: #0c742f; - --theme-success-label: #fff; - --theme-message-color: #753369; - --theme-message-label: #fff; - --theme-community-header-color: #000000; - --theme-community-header-color--hover: #333333; - --theme-background-image-opacity: 100%; - --theme-page-text-opacity-factor: 0.85; - --theme-body-text-opacity-factor: 0.7; -} - -.skin-fandomdesktop .CodeMirror{ - --codemirror-yellow: #a88d00; - --codemirror-light-blue: #0096fb; - --codemirror-blue: #08f; - --codemirror-green: #290; - --codemirror-red: #f50; - --codemirror-dark-red: #a11; - --codemirror-purple: #80c; - --codemirror-pink: #e0e; - --codemirror-light-gray: #929292; - --codemirror-gray: #789797; -} - -.mw-highlight { - --pygments-background: #f4f3f4; - --pygments-err: #f00; - --pygments-c: #408080; - --pygments-k: #008000; - --pygments-o: #666; - --pygments-ch: #408080; - --pygments-cm: #408080; - --pygments-cp: #b17300; - --pygments-cpf: #408080; - --pygments-c1: #408080; - --pygments-cs: #408080; - --pygments-gd: #a00000; - --pygments-gr: #f00; - --pygments-gh: #000080; - --pygments-gi: #009500; - --pygments-go: #808080; - --pygments-gp: #000080; - --pygments-gu: #800080; - --pygments-gt: #04d; - --pygments-kc: #008000; - --pygments-kd: #008000; - --pygments-kn: #008000; - --pygments-kp: #008000; - --pygments-kr: #008000; - --pygments-kt: #b00040; - --pygments-m: #666; - --pygments-s: #ba2121; - --pygments-na: #768826; - --pygments-nb: #008000; - --pygments-nc: #00f; - --pygments-no: #800; - --pygments-nd: #a2f; - --pygments-ni: #7f7f7f; - --pygments-ne: #d2413a; - --pygments-nf: #00f; - --pygments-nl: #818100; - --pygments-nn: #00f; - --pygments-nt: #008000; - --pygments-nv: #19177c; - --pygments-ow: #a2f; - --pygments-w: #808080; - --pygments-mb: #666; - --pygments-mf: #666; - --pygments-mh: #666; - --pygments-mi: #666; - --pygments-mo: #666; - --pygments-sa: #ba2121; - --pygments-sb: #ba2121; - --pygments-sc: #ba2121; - --pygments-dl: #ba2121; - --pygments-sd: #ba2121; - --pygments-s2: #ba2121; - --pygments-se: #b62; - --pygments-sh: #ba2121; - --pygments-si: #b68; - --pygments-sx: #008000; - --pygments-sr: #b68; - --pygments-s1: #ba2121; - --pygments-ss: #19177c; - --pygments-bp: #008000; - --pygments-fm: #00f; - --pygments-vc: #19177c; - --pygments-vg: #19177c; - --pygments-vi: #19177c; - --pygments-vm: #19177c; - --pygments-il: #666; -} - -body { - background: linear-gradient(to bottom, rgba(225, 133, 155, 0) 15%, rgba(225, 133, 155, 0.8)), url(/static/internal-background.png); - min-height: 100vh; - padding: 4px; - margin: 0; -} - -.page__main { - border-radius: 3px; - padding: 24px 36px; -} - -.internal-footer { - max-width: 700px; -} diff --git a/static/main.css b/static/main.css index 33d7264..c44be32 100644 --- a/static/main.css +++ b/static/main.css @@ -81,6 +81,9 @@ p { background-color: var(--theme-page-background-color); padding: 3vw; } +.page table { + color: var(--theme-page-text-color); /* no idea why this needs to be specified, it should inherit from .page */ +} /* table of contents */ .toc { @@ -115,20 +118,6 @@ p { overflow: auto; } -/* table overrides for dark theme pages */ -/* these colours look good in all wikis I tried. colours that don't look good: - --theme-page-background-color--secondary is bad for fallout - --theme-page-accent-mix-color is bad for minecraft */ -.wikitable > tr > th, .wikitable > * > tr > th, .va-table th { - background-color: var(--theme-page-dynamic-color-1--inverted); -} -.wikitable td, .va-table td { - background-color: var(--theme-page-text-mix-color-95); -} -.page table { - color: var(--theme-page-text-color); /* no idea why this needs to be specified, it should inherit from .page */ -} - /* float right. reorganised from their sheet */ .tright { clear: right; @@ -137,7 +126,7 @@ p { } /* indicate wikipedia links */ -.extiw::after, .external::after { +.extiw::after { vertical-align: super; content: "[🡕]"; font-family: serif; @@ -184,23 +173,22 @@ figcaption, .lightbox-caption, .thumbcaption { #mw-content-text .animated > :not(.animated-active), #mw-content-text .animated > .animated-subframe > :not(.animated-active) { display: inline-block; } -.animated-slot__outer { +.animated-slot { display: inline-block; position: relative; overflow: hidden; width: 32px; height: 32px; } -.animated-slot__inner { - display: inline-block; +.animated-slot > * { animation: slide-up calc(var(--steps) * 1s) steps(var(--steps)) infinite; } @keyframes slide-up { 0% { - margin-top: 0px; + transform: translateY(0); } 100% { - margin-top: calc(-34px * var(--steps)); + transform: translateY(calc(-34px * var(--steps))); } }