From 1b2b7c3eb939724696894f31ff27db97b0cac84c Mon Sep 17 00:00:00 2001 From: Andreas Widen Date: Sat, 25 Nov 2023 17:21:37 +0100 Subject: Initial commit. Signed-off-by: Andreas Widen --- apps/base/builder.scm | 95 +++++++ apps/base/templates/about.scm | 57 ++++ apps/base/templates/components.scm | 486 ++++++++++++++++++++++++++++++++++ apps/base/templates/contact.scm | 72 +++++ apps/base/templates/hfge-about.scm | 52 ++++ apps/base/templates/hfge-download.scm | 36 +++ apps/base/templates/hfge-git.scm | 37 +++ apps/base/templates/home.scm | 121 +++++++++ apps/base/templates/menu.scm | 20 ++ apps/base/templates/theme.scm | 143 ++++++++++ apps/base/types.scm | 124 +++++++++ apps/base/utils.scm | 224 ++++++++++++++++ 12 files changed, 1467 insertions(+) create mode 100644 apps/base/builder.scm create mode 100644 apps/base/templates/about.scm create mode 100644 apps/base/templates/components.scm create mode 100644 apps/base/templates/contact.scm create mode 100644 apps/base/templates/hfge-about.scm create mode 100644 apps/base/templates/hfge-download.scm create mode 100644 apps/base/templates/hfge-git.scm create mode 100644 apps/base/templates/home.scm create mode 100644 apps/base/templates/menu.scm create mode 100644 apps/base/templates/theme.scm create mode 100644 apps/base/types.scm create mode 100644 apps/base/utils.scm (limited to 'apps/base') diff --git a/apps/base/builder.scm b/apps/base/builder.scm new file mode 100644 index 0000000..4e1d194 --- /dev/null +++ b/apps/base/builder.scm @@ -0,0 +1,95 @@ +;;; Harmonic Flow web site + +(define-module (apps base builder) + #:use-module (apps base templates about) + #:use-module (apps base templates contact) + #:use-module (apps base templates hfge-about) + #:use-module (apps base templates hfge-download) + #:use-module (apps base templates hfge-git) + #:use-module (apps base templates home) + #:use-module (apps base templates menu) + #:use-module (apps base types) + #:use-module (apps blog utils) + #:use-module (apps media data) + #:use-module (haunt html) + #:use-module (haunt artifact) + #:use-module (haunt post) + #:use-module (haunt utils) + #:use-module (srfi srfi-1) + #:export (builder)) + + +;;; +;;; Application builder. +;;; + +(define (builder site posts) + "Return the list of web resources that compose the app. + + This procedure is a Haunt builder procedure. + + SITE () + A site object that defines all the properties of the website. See + Haunt objects for more information. + + POSTS (list of ) + A list of post objects that represent articles from the blog. See + Haunt objects for more information. + + RETURN (list of ) + A list of page objects that represent the web resources of the + application. See Haunt objects for more information." + (flatten + (list (menu-builder) + (home-builder site posts) + (about-builder) + (contact-builder) + (hfge-about-builder) + (hfge-download-builder) + (hfge-git-builder)))) + + + +;;; +;;; Helper builders. +;;; + + +(define (about-builder) + "Return a Haunt page representing the About page of the website." + (serialized-artifact "about/index.html" (about-t) sxml->html)) + + +(define (contact-builder) + "Return a Haunt page representing the Contact page of the website." + (serialized-artifact "contact/index.html" (contact-t) sxml->html)) + + +(define (hfge-about-builder) + "Return a Haunt page representing the HFGE about page of the website." + (serialized-artifact "hfge-about/index.html" (hfge-about-t) sxml->html)) + + +(define (hfge-download-builder) + "Return a Haunt page representing the HFGE download page of the website." + (serialized-artifact "hfge-download/index.html" (hfge-download-t) sxml->html)) + + +(define (hfge-git-builder) + "Return a Haunt page representing the HFGE git page of the website." + (serialized-artifact "hfge-git/index.html" (hfge-git-t) sxml->html)) + + +(define (home-builder site posts) + "Return a Haunt page representing the Home page of the website." + (let ((context + (list + (cons "screenshots" screenshots) + (cons "posts" (posts/latest posts 3)) + ))) + (serialized-artifact "index.html" (home-t context) sxml->html))) + + +(define (menu-builder) + "Return a Haunt page representing the website menu." + (serialized-artifact "menu/index.html" (menu-t) sxml->html)) diff --git a/apps/base/templates/about.scm b/apps/base/templates/about.scm new file mode 100644 index 0000000..bb7e91d --- /dev/null +++ b/apps/base/templates/about.scm @@ -0,0 +1,57 @@ +;;; Harmonic Flow web site + +(define-module (apps base templates about) + #:use-module (apps base templates components) + #:use-module (apps base templates theme) + #:use-module (apps base types) + #:use-module (apps base utils) + #:use-module (apps i18n) + #:export (about-t)) + + +(define (about-t) + "Return the About page in SHTML." + (theme + #:title (C_ "webpage title" '("About the Site |")) + #:description + (G_ "This website is dedicated to free software primarily in the area of graphics engines but also free software in general.") + #:keywords + (string-split ;TRANSLATORS: |-separated list of webpage keywords + (G_ "About|Harmonic Flow") #\|) + #:active-menu-item (C_ "website menu" "About Site") + #:css (list + (hfweb-url "static/base/css/page.css")) + #:crumbs (list (crumb (C_ "website menu" "About Site") "./")) + #:content + `(main + (section + (@ (class "page centered-block limit-width")) + ,(G_ `(h2 "About the Site")) + + ,(G_ + `(p + "This website is dedicated to free software primarily in the area of + graphics engines but also free software in general." + )) + + ,(G_ + `(p + "The " + ,(G_ `(a (@ (href ,(hfweb-url "blog/"))) " Harmonic Flow Blog")) + " will cover any topics that is of interest (mostly related to free + software in some way)." + )) + + ,(G_ + `(p + "Checkout " + ,(G_ `(a (@ (href ,(hfweb-url "hfge-about/"))) " HFGE 3D graphics engine")) + " for more information about a brand new cross platform 3D graphics + engine currently in development." + )) + + ,(G_ + `(p + "Please use the " + ,(G_ `(a (@ (href ,(hfweb-url "contact/"))) " contact page")) + " for contact information.")))))) diff --git a/apps/base/templates/components.scm b/apps/base/templates/components.scm new file mode 100644 index 0000000..8d7d521 --- /dev/null +++ b/apps/base/templates/components.scm @@ -0,0 +1,486 @@ +;;; Harmonic Flow web site + +(define-module (apps base templates components) + #:use-module (apps aux lists) + #:use-module (apps aux strings) + #:use-module (apps aux sxml) + #:use-module (apps aux web) + #:use-module (apps base types) + #:use-module (apps base utils) + #:use-module (apps i18n) + #:use-module (srfi srfi-1) + #:use-module (ice-9 match) + #:export (breadcrumbs + button-big + button-little + contact-preview + contact->shtml + horizontal-line + horizontal-separator + horizontal-skip + link-more + link-subtle + link-yellow + manual-href + manual-devel-href + manual-link-yellow + navbar + page-indicator + page-selector)) + + +;;; +;;; Components. +;;; + +(define (breadcrumbs crumbs) + "Return an SHTML nav element representing the breadcrumbs. + + CRUMBS (list) + A non-empty list of objects as defined in + (apps base types)." + `(nav + (@ (class "breadcrumbs")) + ,(G_ `(h2 (@ (class "a11y-offset")) "Your location:")) + + ,(G_ `(a (@ (class "crumb") (href ,(hfweb-url))) "Home")) (span " → ") + ,@(separate (crumbs->shtml crumbs) '(span " → ")))) + + +(define (crumbs->shtml crumbs) + "Return the list of CRUMBS as list of SHTML a elements. + + CRUMBS (list) + A non-empty list of objects as defined in + (apps base types)." + (cond ((= (length crumbs) 1) + (cons + `(a + (@ (class "crumb crumb-active") + (href ,(crumb-url (first crumbs)))) + ,(crumb-label (first crumbs))) + '())) + (else + (cons + `(a + (@ (class "crumb") + (href ,(crumb-url (first crumbs)))) + ,(crumb-label (first crumbs))) + (crumbs->shtml (rest crumbs)))))) + + +(define* (button-big #:key (label "Button") (url "#") (light #false)) + "Return an SHTML a element that looks like a big button. + + LABEL (string) + The text for the button. For example: 'Download!'. + + URL (string) + A URL to use for the href attribute of the a element. If not + specified, the value defaults to #. + + LIGHT (boolean) + True if the button is going to be used on a dark background; false + otherwise (this is the default)." + `(a + (@ (class ,(string-append "button-big" (if light " button-light" ""))) + (href ,url)) + ,label)) + + +(define* (button-little #:key (label "Button") (url "#") (active #false)) + "Return an SHTML a element that looks like a little button. + + LABEL (string) + The text for the button. For example: 'Next'. + + URL (string) + A URL to use for the href attribute of the a element. If not + specified, the value defaults to #. + + ACTIVE (boolean) + True if the button should be highlighted as active (on)." + `(a + (@ (class ,(string-append "button-little" + (if active " button-little-active" ""))) + (href ,url)) + ,label)) + + +(define (contact-preview contact) + "Return an SHTML preview of the given contact object. + + CONTACT () + A contact object as defined in (apps base types)." + `(a + (@ (class "item-preview") + (href ,(contact-url contact))) + (h3 ,(contact-name contact)) + (p + ,(string-summarize + (sxml->string* + (match (contact-description contact) + ((and multilingual (((? string?) (? string?)) ...)) + (let ((code %current-lang)) + (match (assoc code multilingual) + ((code blurb) blurb) + (else (assoc "en" multilingual))))) + (blurb + blurb))) + 30) + "…"))) + + +(define (language-tag lang) + `(span (@ (class "button-little button-little-active") + (style "text-align: center; width: 20px; vertical-align: middle")) + ,lang)) + +(define (contact->shtml contact) + "Return an SHTML representation of the given contact object. + + CONTACT () + A contact object as defined in (apps base types)." + `(div + (@ (class "contact-medium")) + (a (@ (href ,(contact-url contact))) (b ,(contact-name contact))) + ,(if (string=? (contact-log contact) "") + "" + `(small + " (" ,(G_ `(a (@ (href ,(contact-log contact))) "archive")) ") ")) + + ;; The description can be a list of language/blurb pairs. + ,(match (contact-description contact) + ((((? string? languages) blurbs) ...) + `(div (@ (id "help-hfweb-mailing-list-description")) + ,@(map (lambda (language blurb) + `(div (@ (style "display: flex; align-items: center; margin: 0 10px 10px 0")) + ,(language-tag language) + (div (@ (lang ,language) (style "flex: 1")) ,blurb))) + languages + blurbs))) + (blurb + blurb)))) + + +(define* (horizontal-separator #:key (light #false)) + "Return an SHTML img element that works as a separator. + + LIGHT (boolean) + True if the separator is going to be used on a dark background; + false otherwise (this is the default)." + `(img + (@ (class "h-separator") + ,(if light + `(src ,(hfweb-url "static/base/img/h-separator.png")) + `(src ,(hfweb-url "static/base/img/h-separator-dark.png"))) + (alt "")))) + +(define (horizontal-skip) + "Return SHTML for a small horizontal space." + `(span (@ (class "hskip")))) + +(define (horizontal-line) + "Return SHTML for a visible separator to be used in a dropdown menu +like a menu item." + `(img (@ (class "hline") + (src ,(hfweb-url "static/base/img/h-separator.png")) + (alt "")))) + + +(define* (link-more #:key (label "More") (url "#") (light #false)) + "Return an SHTML a element that looks like a 'more →' link. + + LABEL (string) + The text for the link. For example: 'Read the manual'. + + URL (string) + A URL to use for the href attribute of the a element. If not + specified, the value defaults to #. + + LIGHT (boolean) + True if the link is going to be used on a dark background; false + otherwise (this is the default)." + `(a + (@ (class ,(string-append "link-more" (if light " link-more-light" ""))) + (href ,url)) + ,label)) + + +(define* (link-subtle #:key (label "link") (url "#")) + "Return an SHTML a element that does not stand too much on white backgrounds. + + LABEL (string) + The text for the link. For example: 'Additional notes'. + + URL (string) + The URL of the link. If not specified, the value defaults to #." + `(a (@ (class "link-subtle") (href ,url)) ,label)) + + +(define* (link-yellow #:key (label "link") (url "#")) + "Return a yellow SHTML a element to use on dark backgrounds. + + LABEL (string) + The text for the link. For example: 'read the manual'. + + URL (string) + The URL of the link. If not specified, the value defaults to #." + `(a (@ (class "link-yellow") (href ,url)) ,label)) + + + + +(define (manual-href label manual-lang _1 subpath _2) + "Return an HTML a element with its href attribute pointing to the +manual. It can be marked for translation as: + + (G_ (manual-href \"some-text\" (G_ \"en\") (G_ \"Some-section.html\"))) + + LABEL (string) + The content of the a element. + + MANUAL-LANG (string) + The normalized language for the Guix manual as produced by +'doc/build.scm' in the Guix source tree, i.e. \"en\" for the English +manual. + + SUBPATH (string) + The same as in the manual-url procedure." + ;; The _ arguments are placeholders for args added by G_, cf. i18n-howto.txt. + `(a (@ (href ,(manual-url subpath #:language manual-lang))) ,label)) + +(define (manual-devel-href label manual-lang _1 subpath _2) + "Similar to 'manual-href', but link to the development manual." + ;; The _ arguments are placeholders for args added by G_, cf. i18n-howto.txt. + `(a (@ (href ,(manual-devel-url subpath #:language manual-lang))) ,label)) + +(define* (manual-link-yellow label manual-lang _1 #:optional (subpath "") _2) + "Return a link-yellow component pointing to the manual. It can be +used like this: + + (manual-link-yellow \"some-text\" (G_ \"en\") \"Package-Management.html\") + + LABEL (string) + The label of the link-yellow. + + MANUAL-LANG (string) + The normalized language for the Guix manual as produced by +'doc/build.scm' in the Guix source tree, i.e. \"en\" for the English +manual. + + SUBPATH (string) + The same as in the manual-url procedure." + ;; The _ arguments are placeholders for args added by G_, cf. i18n-howto.txt. + (link-yellow + #:label label + #:url (manual-url subpath #:language manual-lang))) + + + + +(define* (menu-dropdown #:key (label "Item") (active-item "") (url "#") (items '())) + "Return an SHTML li element representing a dropdown for the navbar. + + LABEL (string) + The text for the dropdown. For example: 'About'. + + ACTIVE-ITEM (string) + A string representing the label of the current active item in the + navigation bar. If the values of LABEL and ACTIVE-ITEM are the + same, the dropdown is highlighted. + + URL (string) + The URL of the web resource referenced by the dropdown. Any + value used for an HTML a element is valid. If not specified, the + value defaults to #. + + ITEMS (list of menu items) + A list of menu items as returned by the menu-item procedure in this + same module. If not provided, the value defaults to an empty list." + (let ((label-hash (number->string (string-hash label)))) + `(li + (@ (class ,(if (string=? (string-downcase label) + (string-downcase active-item)) + "menu-item menu-item-active dropdown dropdown-btn" + "menu-item dropdown dropdown-btn"))) + ,@(let ((id (string-append "visible-dropdown-" label-hash))) + `(;; show dropdown when button is checked: + (style ,(string-append "#" id ":checked ~ #submenu-" label-hash " +{ + min-width: 150px; + width: max-content; + + /* reset to initial values: */ + height: auto; + overflow: visible; +}")) + ;; show uncheck version of button iff button is checked + (style ,(string-append "#" id ":checked \ +~ label[for=all-dropdowns-hidden] +{ + display: inline; +}")) + (style "label[for=all-dropdowns-hidden] +{ + display: none; +}") + ;; show check version of button iff button is unchecked + (style ,(string-append "#" id ":checked ~ label[for=" id "] +{ + display: none; +}")) + (input (@ (class "menu-hidden-input") + (type "radio") + (name "dropdown") + (id ,id))) + (label + (@ (for ,id)) + ,label) + (label + (@ (for "all-dropdowns-hidden")) + ,label))) + (div + (@ (class "submenu") + (id ,(string-append "submenu-" label-hash))) + (div (@ (class "submenu-triangle")) + " ") + (ul ,@items))))) + + +(define* (menu-item #:key (label "Item") (active-item "") (url "#")) + "Return an SHTML li element representing an item for the navbar. + + LABEL (string) + The text for the item. For example: 'About'. + + ACTIVE-ITEM (string) + A string representing the label of the current active item in the + navigation bar. If the values of LABEL and ACTIVE-ITEM are the + same, the menu item is highlighted. + + URL (string) + The URL of the web resource referenced by the menu item. Any + value used for an HTML a element is valid. If not specified, the + value defaults to #." + `(li + (a + (@ (class + ,(if (string=? (string-downcase label) (string-downcase active-item)) + "menu-item menu-item-active" + "menu-item")) + (href ,url)) + ,label))) + + +(define* (navbar #:key (active-item "About")) + "Return an SHTML header element with the given ACTIVE ITEM highlighted." + `(header + (@ (class "navbar")) + + ;; Branding. + (h1 + (a + (@ (class "branding") (href ,(hfweb-url))) + ,(C_ "website menu" `(span (@ (class "a11y-offset")) "Harmonic Flow")))) + + ;; Menu. + (nav (@ (class "menu")) + ,(G_ `(h2 (@ (class "a11y-offset")) "website menu:")) + (input (@ (class "menu-hidden-input") + (type "radio") + (name "dropdown") + (id "all-dropdowns-hidden"))) + (ul + ,(C_ "website menu" (menu-item #:label "Overview" #:active-item active-item #:url (hfweb-url))) + + ,(menu-dropdown #:label (C_ "website menu" "HFGE") + #:active-item active-item + #:items + (list + (C_ "website menu" + (menu-item #:label "About" + #:active-item active-item + #:url (hfweb-url "hfge-about/"))) + (C_ "website menu" + (menu-item #:label "Download" + #:active-item active-item + #:url (hfweb-url "hfge-download/"))) + (C_ "website menu" + (menu-item #:label "Git" + #:active-item active-item + #:url (hfweb-url "hfge-git/"))))) + + ,(menu-dropdown #:label (C_ "website menu" "Media") + #:active-item active-item + #:items + (list + (C_ "website menu" + (menu-item #:label "Screenshots" + #:active-item active-item + #:url (hfweb-url "screenshots/"))))) + + ,(C_ "website menu" (menu-item #:label "Blog" #:active-item active-item #:url (hfweb-url "blog/"))) + + ,(menu-dropdown #:label (C_ "website menu" "About") #:active-item active-item + #:items + (list + (C_ "website menu" (menu-item #:label "About Site" #:active-item active-item #:url (hfweb-url "about/"))) + (horizontal-line) + (C_ "website menu" (menu-item #:label "Contact" #:active-item active-item #:url (hfweb-url "contact/"))))) + ,(horizontal-skip))) + + + ;; Menu button. + (a + (@ (class "menu-btn") + (href ,(hfweb-url "menu/"))) ""))) + +(define (page-indicator page-number total-pages) + "Return an SHTML span element in the form 'page X of Y' if there is + more than one page. Otherwise, return an empty string. + + PAGE-NUMBER (number) + The number of the page that the user is seeing. + + TOTAL-PAGES (number) + The total number of pages that should be displayed." + (if (> total-pages 1) + (G_ `(span + (@ (class "page-number-indicator")) + " (Page " ,(number->string page-number) + " of " ,(number->string total-pages) ")")) + "")) + + +(define (page-selector pages active-page base-url) + "Return an SHTML nav element representing a page selection widget. + + PAGES (number) + The total number of pages that should be displayed. + + ACTIVE-PAGE (number) + The number of the page that should be displayed as active. + + BASE-URL (string) + Absolute URL path to prepend to page numbers. For example: + '/en/blog'. This would result in URLs like: '/en/blog/page/N', + where N is the number of the page." + `(nav + (@ (class "page-selector")) + (h3 + (@ (class "a11y-offset")) + ,(G_ (string-append "Page " (number->string active-page) " of " + (number->string pages) ". Go to another page: "))) + ,(if (> pages 1) + (map + (lambda (page-number) + (list + (button-little + #:label page-number + #:url (url-path-join base-url "page" + (number->string page-number) "") + #:active (= page-number active-page)) + " ")) ; NOTE: Force space for readability in non-CSS browsers. + (iota pages 1)) + ""))) diff --git a/apps/base/templates/contact.scm b/apps/base/templates/contact.scm new file mode 100644 index 0000000..88ab2a8 --- /dev/null +++ b/apps/base/templates/contact.scm @@ -0,0 +1,72 @@ +;;; Harmonic Flow web site + +(define-module (apps base templates contact) + #:use-module (apps base templates components) + #:use-module (apps base templates theme) + #:use-module (apps base types) + #:use-module (apps base utils) + #:use-module (apps i18n) + #:export (contact-t)) + + +(define (contact-t) + "Return the Contact page in SHTML." + (theme + #:title (C_ "webpage title" '("Contact |")) + #:description + (G_ "A list of channels to communicate with Harmonic Flow directly about anything you want.") + #:keywords + (string-split ;TRANSLATORS: |-separated list of webpage keywords + (G_ "Contact|Harmonic Flow") #\|) + #:active-menu-item (C_ "website menu" "Contact") + #:css (list + (hfweb-url "static/base/css/page.css")) + #:crumbs (list (crumb (C_ "website menu" "Contact") "./")) + #:content + `(main + (section + (@ (class "page centered-block limit-width")) + ,(G_ `(h2 "Contact")) + + ,(G_ + `(p + "Contact info email / xmpp: andreas at harmonicflow dot o r g")) + + ,(G_ + `(p + "Please download & import the following " + ,(G_ `(a (@ (href ,(hfweb-url "static/gnupg-pubkeys/andreas-pubkey.asc"))) " GPG key")) + " if you want to send me encrypted email:" + )) + + ,(G_ + `(pre + "gpg --import /path/to/andreas-pubkey.asc")) + ,(G_ + `(p + ".. or by using the following command:" + )) + + ,(G_ + `(pre + "gpg --recv-keys 0x14121B58362B5F22")) + + ,(G_ + `(p + "The public key fingerprint should be:")) + + ,(G_ + `(pre + "9ECF C528 9712 3654 F76B 63FD 1412 1B58 362B 5F22")) + + ,(G_ + `(p + "For more information about encryption and GnuPG, see: " + ,(G_ `(a (@ (href "https://www.gnupg.org")) + "GnuPG website.")) + )) + + ,(G_ + `(p + "The above public key is also used for signing releases.")) + )))) diff --git a/apps/base/templates/hfge-about.scm b/apps/base/templates/hfge-about.scm new file mode 100644 index 0000000..ab0b795 --- /dev/null +++ b/apps/base/templates/hfge-about.scm @@ -0,0 +1,52 @@ +;;; Harmonic Flow web site + +(define-module (apps base templates hfge-about) + #:use-module (apps base templates components) + #:use-module (apps base templates theme) + #:use-module (apps base types) + #:use-module (apps base utils) + #:use-module (apps i18n) + #:export (hfge-about-t)) + + +(define (hfge-about-t) + "Return the About HFGE page in SHTML." + (theme + #:title (C_ "webpage title" '("About HFGE |")) + #:description + (G_ "HFGE is a cross platform 3D game engine written in C++ and distributed under the zlib license.") + #:keywords + (string-split ;TRANSLATORS: |-separated list of webpage keywords + (G_ "HFGE|Harmonic Flow|Graphics Engine|Game Engine|3D game engine|cross platform|Free Software|C++|Libre software|Graphics Programming|Vulkan|Download") #\|) + #:active-menu-item (C_ "website menu" "About") + #:css (list + (hfweb-url "static/base/css/page.css")) + #:crumbs (list (crumb (C_ "website menu" "About HFGE") "./")) + #:content + `(main + (section + (@ (class "page centered-block limit-width")) + ,(G_ `(h2 "About HFGE")) + + ,(G_ + `(p + "HFGE is a new cross platform 3D engine currently in development. HFGE + is written in C++ and will initially support Windows and GNU/Linux + platforms. HFGE will use a modern renderer in the form of Vulkan. + ")) + + ,(G_ + `(p + "HFGE is free / libre software and will be distributed under the zlib + license. This license allows you to use HFGE freely in any software. + ")) + + ,(G_ + `(p + "More information, " + ,(G_ `(a (@ (href ,(hfweb-url "hfge-download/"))) " downloads")) + " and" + ,(G_ `(a (@ (href ,(hfweb-url "hfge-git/"))) " git repoistory")) + " will be available once it's ready for public release." + )) + )))) diff --git a/apps/base/templates/hfge-download.scm b/apps/base/templates/hfge-download.scm new file mode 100644 index 0000000..0e91657 --- /dev/null +++ b/apps/base/templates/hfge-download.scm @@ -0,0 +1,36 @@ +;;; Harmonic Flow web site + +(define-module (apps base templates hfge-download) + #:use-module (apps base templates components) + #:use-module (apps base templates theme) + #:use-module (apps base types) + #:use-module (apps base utils) + #:use-module (apps i18n) + #:export (hfge-download-t)) + + +(define (hfge-download-t) + "Return the Download HFGE page in SHTML." + (theme + #:title (C_ "webpage title" '("Download HFGE |")) + #:description + (G_ "Download the latest version of HFGE. Source code is available.") + #:keywords + (string-split ;TRANSLATORS: |-separated list of webpage keywords + (G_ "Download|HFGE|Source Code") #\|) + #:active-menu-item (C_ "website menu" "Download") + #:css (list + (hfweb-url "static/base/css/page.css")) + #:crumbs (list (crumb (C_ "website menu" "Download HFGE") "./")) + #:content + `(main + (section + (@ (class "page centered-block limit-width")) + ,(G_ `(h2 "Download HFGE")) + + ,(G_ + `(p + "HFGE is a new cross platform 3D engine currently in development. Once + HFGE is released you'll be able to download HFGE from here :) + ")) + )))) \ No newline at end of file diff --git a/apps/base/templates/hfge-git.scm b/apps/base/templates/hfge-git.scm new file mode 100644 index 0000000..7cc9266 --- /dev/null +++ b/apps/base/templates/hfge-git.scm @@ -0,0 +1,37 @@ +;;; Harmonic Flow web site + +(define-module (apps base templates hfge-git) + #:use-module (apps base templates components) + #:use-module (apps base templates theme) + #:use-module (apps base types) + #:use-module (apps base utils) + #:use-module (apps i18n) + #:export (hfge-git-t)) + + +(define (hfge-git-t) + "Return the HFGE git page in SHTML." + (theme + #:title (C_ "webpage title" '("HFGE git repository |")) + #:description + (G_ "Get the latest development updates through HFGE git repository.") + #:keywords + (string-split ;TRANSLATORS: |-separated list of webpage keywords + (G_ "Git|Repository|HFGE") #\|) + #:active-menu-item (C_ "website menu" "Git") + #:css (list + (hfweb-url "static/base/css/page.css")) + #:crumbs (list (crumb (C_ "website menu" "HFGE Git repository") "./")) + #:content + `(main + (section + (@ (class "page centered-block limit-width")) + ,(G_ `(h2 "HFGE Git repository")) + + ,(G_ + `(p + "HFGE is a new cross platform 3D engine currently in development. Once + HFGE is released you'll be able to get access to the latest + development updates through public Git repository from here :) + ")) + )))) \ No newline at end of file diff --git a/apps/base/templates/home.scm b/apps/base/templates/home.scm new file mode 100644 index 0000000..464cb0f --- /dev/null +++ b/apps/base/templates/home.scm @@ -0,0 +1,121 @@ +;;; Harmonic Flow web site + +(define-module (apps base templates home) + #:use-module (apps base templates components) + #:use-module (apps base templates theme) + #:use-module (apps base types) + #:use-module (apps base utils) + #:use-module (apps blog templates components) + #:use-module (apps media templates components) + #:use-module (apps media types) + #:use-module (apps i18n) + #:export (home-t)) + + +(define (home-t context) + "Return the Home page in SHTML using the data in CONTEXT." + (theme + #:title (C_ "webpage title" + '("HFGE 3D engine, coding and free software |")) + #:description + (G_ "This website is dedicated to free software primarily in the area of graphics engines but also free software in general.") + #:keywords + (string-split ;TRANSLATORS: |-separated list of webpage keywords + (G_ "Harmonic Flow|HFGE|Free Software|C++|Libre software|Engine|Game Engine|Graphics|3D|2D|Programming|Vulkan") #\|) + #:active-menu-item (C_ "website menu" "Overview") + #:css (list + (hfweb-url "static/base/css/item-preview.css") + (hfweb-url "static/base/css/index.css")) + #:content + `(main + ;; Featured content. + (section + (@ (class "featured-content")) + ,(G_ `(h2 (@ (class "a11y-offset")) "Summary")) + (ul + ;; Libre: + ,(G_ + `(li + ,(G_ `(b "Libre.")) + ,(G_ (link-yellow + #:label " HFGE" + #:url (hfweb-url "hfge-about/"))) + " will be distributed under the zlib license. This license allows you + to use HFGE freely in any software (it respects your freedom). " + )) + ;; Vulkan: + ,(G_ + `(li + ,(G_ `(b "Vulkan.")) + ,(G_ (link-yellow + #:label " HFGE" + #:url (hfweb-url "hfge-about/"))) + " comes with a modern, low level, low overhead, cross platform + renderer in the form of Vulkan (additional renderers can be added as + plugins if needed)." + )) + ;; Cross platform: + ,(G_ + `(li + ,(G_ `(b "Cross platform.")) + ,(G_ (link-yellow + #:label " HFGE" + #:url (hfweb-url "hfge-about/"))) + " will initially support Windows and GNU/Linux. More platforms such + as Android will be added later on." + )) + ;; Tools: + ,(G_ + `(li + ,(G_ `(b "Tools.")) + ,(G_ (link-yellow + #:label " HFGE" + #:url (hfweb-url "hfge-about/"))) + " comes with a few useful tools for generating bitmap fonts, texture + atlases, resource archives and a hash checksum tool." + )) + ) + + (div + (@ (class "action-box centered-text")) + ,(button-big + #:label (C_ "button" "MORE INFO") + #:url (hfweb-url "hfge-about/") + #:light #true) + " " ; A space for readability in non-CSS browsers. + ,(button-big + #:label (C_ "button" "DOWNLOAD") + #:url (hfweb-url "hfge-download/") + #:light #true))) + + ;; Screenshots: + (section + (@ (class "discovery-box")) + ,(G_ `(h2 "Screenshots")) + + ,(G_ + `(p + (@ (class "limit-width centered-block")) + "A few early development screenshots of " + ,(G_ (link-yellow #:label "HFGE" + #:url (hfweb-url "hfge-about/"))) + " in action.")) + + ,(screenshots-box (context-datum context "screenshots")) + + ;;,(horizontal-separator #:light #true) + ) + + ;; Latest Blog posts: + (section + (@ (class "centered-text")) + ,(G_ `(h2 "Blog")) + + ,@(map post-preview (context-datum context "posts")) + + (div + (@ (class "action-box centered-text")) + ,(button-big + #:label (C_ "button" "ALL POSTS") + #:url (hfweb-url "blog/")))) + ))) diff --git a/apps/base/templates/menu.scm b/apps/base/templates/menu.scm new file mode 100644 index 0000000..734ec50 --- /dev/null +++ b/apps/base/templates/menu.scm @@ -0,0 +1,20 @@ +;;; Harmonic Flow web site + +(define-module (apps base templates menu) + #:use-module (apps base templates components) + #:use-module (apps base templates theme) + #:use-module (apps base utils) + #:use-module (apps i18n) + #:export (menu-t)) + + +(define (menu-t) + "Return the Menu page in SHTML." + (theme + #:title (C_ "webpage title" '("Menu")) + #:description (G_ "Website menu.") + #:keywords + (string-split ;TRANSLATORS: |-separated list of webpage keywords + (G_ "Harmonic Flow|HFGE|Free Software|C++|Libre software|Graphics Programming|Vulkan") #\|) + #:active-menu-item (C_ "website menu" "Menu") + #:css (list (hfweb-url "static/base/css/menu.css")))) diff --git a/apps/base/templates/theme.scm b/apps/base/templates/theme.scm new file mode 100644 index 0000000..a944077 --- /dev/null +++ b/apps/base/templates/theme.scm @@ -0,0 +1,143 @@ +;;; Harmonic Flow web site + +(define-module (apps base templates theme) + #:use-module (apps base templates components) + #:use-module (apps base utils) + #:use-module (apps i18n) + #:export (theme)) + + +(define* (theme #:key + (lang-tag %current-ietf-tag) + (title '()) + (description "") + (keywords '()) + (index? #true) + (active-menu-item (C_ "website menu" "About")) + (css '()) + (scripts '()) + (crumbs '()) + (content '(div ""))) + "Return an SHTML document using the website's theme. + + LANG-TAG (string) + IETF language tag. This is used to specify the language of the + document. For example: en, en-CA. If not provided, the value + defaults to the currently built language, i.e. the + %current-ietf-tag from (apps i18n). + + TITLE (list) + A list of strings to form the value of the title element of the + document. The elements of the list are joined together with em + dashes as separators between them. For example, a list with two + strings like 'Hello', and 'Blog' will result in a title like + 'Hello — Blog — Guix'. + + DESCRIPTION (string) + The description of the document. This is the value used for the + description meta element. + + KEYWORDS (list) + A list of keyword strings that will be used as the value for + the keywords meta element of the document. + + INDEX? (boolean) + Indicate whether the page should be indexed by Internet robots, + such as search engine robots. If not provided, it defaults to + true. + + ACTIVE-MENU-ITEM (string) + The label of the menu item in the navigation bar that should be + highlighted to indicate the current section of the website that + is being browsed. If not provided, the value defaults to 'About'. + + CSS (list) + A list of strings that represent absolute URL paths to additional + style sheets. For example: '/static/app/css/style.css'. If not + provided, the value defaults to an empty list. + + SCRIPTS (list) + A list of strings that represent absolute URL paths to additional + script files. For example: '/static/app/js/builds.js'. If not + provided, the value defaults to an empty list. + + CRUMBS (list) + A list of objects as defined in (apps base types). This + objects are used to form the breadcrumbs of the website. + + CONTENT (SHTML) + A main element with the content of the page. For example: + '(main (h2 'Hello World!') (p 'Once upon a time...'))." + `((doctype "html") + + (html + (@ (lang ,lang-tag)) + + (head + ,(if (null? title) + `(title ,(C_ "webpage title" "Harmonic Flow")) + `(title ,(string-join (append title + (C_ "webpage title" '("Harmonic Flow")))))) + (meta (@ (charset "UTF-8"))) + (meta (@ (name "keywords") (content ,(string-join keywords ", ")))) + (meta (@ (name "description") (content ,description))) + (meta (@ (name "viewport") (content "width=device-width, initial-scale=1.0"))) + ;; Info for Internet robots. + ,(if index? + "" + '(meta (@ (name "robots") (content "noindex")))) + ;; Menu prefetch. + (link (@ (rel "prefetch") (href ,(hfweb-url "menu/index.html")))) + ;; Base CSS. + (link (@ (rel "stylesheet") (href ,(hfweb-url "static/base/css/elements.css")))) + (link (@ (rel "stylesheet") (href ,(hfweb-url "static/base/css/common.css")))) + (link (@ (rel "stylesheet") (href ,(hfweb-url "static/base/css/messages.css")))) + (link (@ (rel "stylesheet") (href ,(hfweb-url "static/base/css/navbar.css")))) + (link (@ (rel "stylesheet") (href ,(hfweb-url "static/base/css/breadcrumbs.css")))) + (link (@ (rel "stylesheet") (href ,(hfweb-url "static/base/css/buttons.css")))) + (link (@ (rel "stylesheet") (href ,(hfweb-url "static/base/css/footer.css")))) + (link (@ (rel "stylesheet") (href ,(hfweb-url "static/base/highlight/styles/stackoverflow-light.min.css")))) + ;; Additional CSS. + ,@(map (lambda (style-sheet) + `(link (@ (rel "stylesheet") (href ,style-sheet)))) + css) + ;; Feeds. + (link (@ (type "application/atom+xml") (rel "alternate") + (title ,(C_ "webpage title" "Harmonic Flow — Activity Feed")) + (href ,(hfweb-url "feeds/blog.atom")))) + (link (@ (rel "icon") (type "image/png") + (href ,(hfweb-url "static/base/img/icon.png")))) + (link (@ (rel "icon") (type "image/svg+xml") (sizes "any") + (href ,(hfweb-url "static/base/img/icon.svg")))) + ;; Scripts: + (script (@ (src ,(hfweb-url"static/base/highlight/highlight.min.js")))) + (script (("hljs.highlightAll();"))) + ;; Additional scripts. + ,@(map (lambda (script) + `(script (@ (src ,script)) "")) + scripts)) + + (body + ,(navbar #:active-item active-menu-item) + + ,(if (null? crumbs) "" (breadcrumbs crumbs)) + + ,content + ,(G_ + `(footer + "Powered by " + ,(G_ `(a + (@ (class "link-yellow") + (href ,(gnu-url "software/guile/"))) + "GNU Guile")) + ". Website " + ,(G_ `(a + (@ (class "link-yellow") + (href "https://git.harmonicflow.org/cgi-bin/cgit.cgi/hf-web.git/")) + " Source code")) + " is licensed the " + ,(G_ `(a + (@ (class "link-yellow") + (href ,(gnu-url "licenses/agpl-3.0.html"))) + "GNU AGPL")) + ".")))))) diff --git a/apps/base/types.scm b/apps/base/types.scm new file mode 100644 index 0000000..91e9729 --- /dev/null +++ b/apps/base/types.scm @@ -0,0 +1,124 @@ +;;; Harmonic Flow web site + +(define-module (apps base types) + #:use-module (srfi srfi-9) + #:export (contact + contact? + contact-description + contact-log + contact-name + contact-url + context-datum + crumb + crumb? + crumb-label + crumb-url)) + + +;;; +;;; Data types. +;;; + +;;; Contact (record type) +;;; --------------------- +;;; +;;; A contact object represents a contact medium such as a mailing +;;; list, IRC channel, email address, etc. +;;; +;;; Objects of this type can be created with the "contact" +;;; procedure as well (see Helper procedures below). +;;; +;;; Fields: +;;; +;;; name (string) +;;; The name of the contact medium. For example: +;;; "Development mailing list". +;;; +;;; description (SXML) +;;; A short description. For example: +;;; '(p "Discussion about the development of Guix."). +;;; +;;; url (string) +;;; A URL to the main page of the contact medium. +;;; +;;; log (string) +;;; A URL to the archive or log of previous public communications +;;; help on the contact medium (empty string if there is no log). +;;; +(define-record-type + (make-contact name description url log) + contact? + (name contact-name) + (description contact-description) + (url contact-url) + (log contact-log)) + +;;; Helper procedures. + +(define* (contact #:key (name "") (description "") (url "") (log "")) + "Return a object with the given attributes." + (make-contact name description url log)) + + + +;;; Context (association list) +;;; -------------------------- +;;; +;;; A context object is a collection of data to be rendered in the +;;; template of a web resource. +;;; +;;; A context can have any number of custom keys depending on the +;;; requirements of a given template. +;;; +;;; The following is an example of a context object to be used with an +;;; SHTML template: +;;; +(define some-context + (list + (cons "LANGUAGE" "es") + (cons "CHARSET" "UTF-8") + (cons "AUTHOR" "Jane Roe") + (cons "FRIENDS" (list "John Doe" "Nyoro N." "Jack the Lad")))) + +;;; Helper procedures. + +(define (context-datum context key) + "Return the value of KEY in the given CONTEXT. + + CONTEXT (Context) + See more information about the Context type in (apps base types). + + KEY (atom) + Any atomic value allowed for association list keys." + (assoc-ref context key)) + + + +;;; Crumb (record type) +;;; ------------------- +;;; +;;; A crumb object represents one of the parts of a breadcrumbs +;;; component of a website. +;;; +;;; Objects of this type can be created with the "crumb" procedure as +;;; well (see Helper procedures below). +;;; +;;; Fields: +;;; +;;; label (string) +;;; A human readable name for the crumb. For example: "Blog". +;;; +;;; url (string) +;;; The URL to the web resource related to the crumb. +;;; +(define-record-type + (make-crumb label url) + crumb? + (label crumb-label) + (url crumb-url)) + +;;; Helper procedures. + +(define (crumb label url) + "Return a object with the given attributes." + (make-crumb label url)) diff --git a/apps/base/utils.scm b/apps/base/utils.scm new file mode 100644 index 0000000..31e18ea --- /dev/null +++ b/apps/base/utils.scm @@ -0,0 +1,224 @@ +;;; Harmonic Flow web site + +(define-module (apps base utils) + #:use-module (apps aux lists) + #:use-module (apps aux system) + #:use-module (apps base types) + #:use-module (apps i18n) + #:use-module (haunt artifact) + #:use-module (ice-9 i18n) + #:use-module (ice-9 match) + #:use-module (srfi srfi-1) + #:export (gnu-url + hfweb-url + locale-display-name + manual-url + manual-devel-url + manual-url-with-language + number* + paginate + packages-url)) + + +;;; +;;; Harmonic Flow variables. +;;; + +(define* (gnu-url #:optional (path "")) + "Append PATH to GNU.org URL. + + PATH (string) + An optional relative URL path to a resource. For example: + 'software/guile/'. + + RETURN VALUE (string) + A URL. For example: https://gnu.org/software/guile/." + (string-append "https://gnu.org/" path)) + +(define hfweb-root-url-path + ;; Path to hfge site: + (let ((path (match (getenv "HFGE_WEB_SITE_LOCAL") + ;; If we are trying out the website locally, use "/" as the root. + ("yes" "/") + (else (or (getenv "HFGE_WEB_SITE_ROOT_PATH") "/"))))) + (make-parameter + path + ;; When setting hfweb-root-url-path, make it end in a slash. + (lambda (path) + (if (string-suffix? "/" path) + path + (string-append path "/")))))) + +(define (locale-display-name) + "Return the display name of the current locale." + ;; TRANSLATORS: The locale’s display name; please include a country + ;; code like in English (US) *only* if there are multiple + ;; translations for the same language. + (let ((str '(G_ "English"))) + ;;; XXX: If we ever add a separate English (UK) translation, then + ;;; change the display name to English (US), but maybe do not + ;;; change str, because it would break translated PO files. + (gettext (cadr str)))) + + + +;;; +;;; URL linking. +;;; + + +(define* (hfweb-url #:optional (subpath "") #:key (localize #t)) + "Append SUBPATH to Harmonic Flow root URL path (see hfweb-root-url-path). + + SUBPATH (string) + An optional relative URL path to a resource in the Harmonic Flwo path. + For example: 'indeed/something-XYZ/'. + + LOCALIZE (boolean) + Whether to prepend the result of 'localized-root-path' to the URL path. + + RETURN VALUE (string) + A URL path. For example: /indeed/something/-XYZ/." + (string-append (hfweb-root-url-path) + (if localize (localized-root-path subpath) "") + subpath)) + + +(define* (manual-url #:optional (subpath "") + #:key (language "en")) + "Append SUBPATH to the Harmonic Flow manual URL path. + + SUBPATH (string) + An optional relative URL path to a section of the manual. + For example: 'SomeFile.html'. + + RETURN VALUE (string) + A URL path. For example: + /indeed/SomeFile.html." + (string-append + (hfweb-url (string-append (string-append "manual/" language + "/html_node/") + subpath) #:localize #f))) + +(define* (manual-devel-url #:optional (subpath "") + #:key (language "en")) + "Similar to 'manual-url', but link to the development manual." + (string-append + (hfweb-url (string-append (string-append "manual/devel/" language + "/html_node/") + subpath) #:localize #f))) + +(define* (manual-url-with-language _ language #:optional (subpath "")) + "Shorthand for manual-url without keywords for prettier output +PO files when marked for translation. It can be marked for translation +as: + + (G_ (manual-url-with-language (G_ \"en\") (G_ \"Some-section.html\"))) + + LANGUAGE (string) + Normalized language for the Guix manual as produced by +'doc/build.scm' in the Guix source tree, i.e. \"en\" for the English +manual. + + SUBPATH (string) + Like manual-url. + + RETURN VALUE (string) + A URL path. For example: + /software/guix/manual/en/html_node/System-installation.html." + ;; The _ argument is a placeholder for an arg added by G_, cf. i18n-howto.txt. + (manual-url subpath #:language language)) + + +;;; +;;; Helper procedures. +;;; + +(define (number* number) + "Return NUMBER correctly formatting according to English conventions." + (number->locale-string number 0 + (or (false-if-exception + (make-locale LC_ALL "en_US.utf8")) + (make-locale LC_ALL "en_US.UTF-8")))) + + +(define* (paginate #:key dataset (limit 30) base-path template (context '()) writer) + "Distribute the objects of the DATASET in pages. + + DATASET (list) + A list with any kind of object. + + LIMIT (integer) + The maximum number of objects that should appear in a page. + + The limit is optional. If not provided, it defaults to 30. + + BASE-PATH (string) + A system path relative to the website directory where all the + pages will be written to. For example: 'blog' or 'blog/tags'. + + In the latter example, pages would be written to files in a path + like 'blog/tags/page/PAGE_NUMBER/index.html'. + + TEMPLATE (procedure) + A procedure that accepts a context and returns an SXML tree. + + CONTEXT (context) + A context object as defined in (apps base types). The context + holds additional data to insert into the TEMPLATE. + + The context is optional, and will always be extended to include + the following data that can be used in the TEMPLATE: + + items (list) + The list of items to insert into the page. + + total-pages (integer) + The number of pages generated to distribute all items. + + page-number (integer) + The number of the page. + + WRITER + A procedure that writes the page into a given format. See Haunt's + 'sxml->html' writer in the (haunt html) module, for example. + + RETURN VALUE (list) + A list of objects as defined in (haunt page) module." + (let* ((grouped-data (list-group dataset limit)) + (total-pages (cons "total-pages" (length grouped-data)))) + ;; Read the following like (cons Page ListOfPages): + (cons + ;; Page + ;; This is the cover of the pages. For example, the resource + ;; located in a path such as /blog/, which is identical to the + ;; resource available in /blog/page/1/. + (let* ((page-number (cons "page-number" 1)) + (path (path-join base-path "index.html")) + (items + (match grouped-data + (() + (cons "items" '())) + ((head _ ...) + (cons "items" head)))) + (new-context + (append context + (list items page-number total-pages)))) + + (serialized-artifact path (template new-context) writer)) + ;; ListOfPages + ;; This is a list of pages that are the actual ordered pages + ;; located in paths such as /blog/page/NUMBER/. + (map + (lambda (index) + (let* ((page-number (cons "page-number" (+ index 1))) + (path (path-join base-path + "page" + (number->string (+ index 1)) + "index.html")) + (items (cons "items" (list-ref grouped-data index))) + (new-context + (append context (list items page-number total-pages)))) + (serialized-artifact path (template new-context) writer))) + + (iota (length grouped-data)))))) -- cgit v1.2.3-54-g00ecf