diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c5e16b5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: Check pull request + +on: + pull_request: + branches: [main] + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.3" + bundler-cache: true + + - uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Validate front matter + run: ruby script/validate.rb + + - name: Install Tailwind + run: npm install --no-audit --no-fund + + - name: Build stylesheet + run: npm run css + + - name: Build site + run: bundle exec jekyll build --trace + env: + JEKYLL_ENV: production diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..2e866fe --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,60 @@ +name: Build and deploy + +on: + push: + branches: [main] + workflow_dispatch: +# No scheduled rebuild needed: the browser recomputes which entries are +# ongoing, scheduled or closed from their timestamps (assets/js/status.js). + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.3" + bundler-cache: true + + - uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Validate front matter + run: ruby script/validate.rb + + - name: Install Tailwind + run: npm install --no-audit --no-fund + + - name: Build stylesheet + run: npm run css + + - name: Build site + run: bundle exec jekyll build --trace + env: + JEKYLL_ENV: production + + - uses: actions/upload-pages-artifact@v3 + with: + path: _site + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/404.html b/404.html new file mode 100644 index 0000000..c202ca8 --- /dev/null +++ b/404.html @@ -0,0 +1,21 @@ +--- +layout: default +title: Page not found +permalink: /404.html +sitemap: false +--- + +
+ + {%- include icon.html name="circle-alert" class="h-7 w-7" -%} + +

Page not found

+

+ This announcement does not exist, or the link has changed. +

+ + {%- include icon.html name="arrow-left" class="h-4 w-4" -%} + Back to Home + +
diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..af608aa --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +source "https://rubygems.org" + +gem "jekyll", "~> 4.4" +gem "jekyll-sitemap", "~> 1.4" + +# Required on Ruby 3.x for `jekyll serve`. +gem "webrick", "~> 1.8" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5554fb7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 VIB Data Core + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4efb7fa --- /dev/null +++ b/README.md @@ -0,0 +1,150 @@ +# VIB Data Core — announcements + +Public notice board for the services run by VIB Data Core: +**https://vib-data-core.github.io/status** + +Everything on that page comes from Markdown files in this repository. Posting +an announcement means adding one file — no HTML, no CSS, no build step on your +side. + +## Quick start: post an announcement + +Copy [`_announcements/TEMPLATE.md`](_announcements/TEMPLATE.md) to a new file +next to it and edit it. On GitHub: open the template, **Copy raw file**, then +in [`_announcements/`](_announcements/) click **Add file → Create new file**, +name it `YYYY-MM-DD-short-slug.md` — for example +`2026-09-19-project-storage-slow.md` — and paste. + + +```yaml +--- +title: Slower than usual access to Project Storage +start: 2026-09-19 09:30:00 +type: unplanned +services_affected: + - project-storage +summary: >- + One or two sentences shown on the card and in the history. +--- + +Markdown body +``` + +Leave `end:` out entirely while it is still going on. When it is over, edit the +same file and add the end time: + +```yaml +end: 2026-09-19 18:00:00 +``` + +For planned work, set `type: planned` and give both `start` and `end` up front: + +```yml +--- +title: Planned maintenance of the Electronic Lab Notebook +start: 2026-10-06 19:00:00 +end: 2026-10-06 23:00:00 +type: planned +services_affected: + - eln +summary: >- + The Electronic Lab Notebook is unavailable for about four hours. +--- +``` + +The page rebuilds automatically after the change lands on `main`. + +## Updates during a long announcement + +A long-running announcement can carry a list of updates. Newest first or +oldest first, both work; the page sorts them. The most recent update is also +shown on the card on the landing page. + +```yaml +updates: + - time: 2026-09-20 11:00:00 + body: >- + Performance has improved for most users. + - time: 2026-09-19 10:15:00 + body: >- + We are aware of the slower access and are looking into it. +``` + +## Front matter reference + +| Field | Required | Type | Notes | +| --- | --- | --- | --- | +| `title` | yes | text | Keep it under ~90 characters. Describe the impact, not the cause. | +| `start` | yes | date-time | Unquoted, **no timezone offset**: `2026-09-19 09:30:00`. Always Belgian local time — summer and winter time are handled for you. | +| `end` | no | date-time | Omit while it is still going on. Once it is in the past, the entry moves to the history page. | +| `type` | yes | keyword | `unplanned` or `planned`. | +| `services_affected` | yes | list | Ids from [`_data/services.yml`](_data/services.yml). Unknown ids fail the build check. | +| `summary` | recommended | text | One or two sentences, shown on cards and in the history. | +| `updates` | no | list | Chronological updates during a long announcement, each one a `time` and a `body`. See the commented-out block in the template. | + +Times carry no offset because every time on this page is Belgian local time. +[`_plugins/local_times.rb`](_plugins/local_times.rb) reads them that way; YAML +would otherwise take a bare time for UTC and the page would move the entry an +hour or two late. + +### Services + +Defined in [`_data/services.yml`](_data/services.yml), and they mirror the Data +Core catalogue (the services listed in Connect). One announcement can cover +several of them. Use the `id` in front matter; the `name` is what readers see: + +```yaml +- id: project-storage + name: Project Storage + description: Laboris nisi ut aliquip ex ea commodo consequat. +``` + +The `description` only surfaces as the tooltip on a service chip, and the ones +checked in are placeholder text — replace them with the catalogue wording. + +If the catalogue gains a service, add it here in the same change. Ids are +lowercase with dashes and should not change afterwards — they appear in +shareable filter links such as `/history/?services=project-storage,usegalaxy`. + +## Working on it locally + +You need Ruby (3.1+) and Node (18+). + +```bash +bundle install # Jekyll and friends +npm install # Tailwind CLI + +npm run serve # builds the CSS, watches it, and serves on http://localhost:3002/status/ +``` + +Other commands: + +```bash +npm run css # one-off, minified stylesheet +npm run build # CSS + full Jekyll build into _site/ +npm run validate # check all entries against the vocabularies +``` + +`assets/css/main.css` is generated and git-ignored — never edit it by hand, +edit [`assets/css/tailwind.css`](assets/css/tailwind.css) instead. + + +### Checks on every change + +[`script/validate.rb`](script/validate.rb) runs in CI and fails on: + +- missing `title`, `start` or `type` +- an unknown `type`, or a retired `severity:`/`kind:` key +- quoted or malformed date-times, and an `end` before the `start` +- a `Z` or `+00:00` offset on a time, which is indistinguishable from a bare + Belgian local time and would silently shift the entry by an hour or two +- missing or unknown service ids +- malformed `updates` entries + +It also prints warnings (empty body, missing summary, odd file name) that do +not block the change. + + +## Licence + +Code in this repository is MIT licensed (see [LICENSE](LICENSE)). diff --git a/_announcements/2026-06-02-nulla-vitae-elit-libero.md b/_announcements/2026-06-02-nulla-vitae-elit-libero.md new file mode 100644 index 0000000..0f0e81c --- /dev/null +++ b/_announcements/2026-06-02-nulla-vitae-elit-libero.md @@ -0,0 +1,14 @@ +--- +title: Nulla vitae elit libero a pharetra augue +start: 2026-06-02 16:00:00 +end: 2026-06-02 16:45:00 +type: planned +services_affected: + - software-hosting +summary: >- + Sed posuere consectetur est at lobortis, aenean eu leo quam pellentesque + ornare. +--- + +Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac +cursus commodo, tortor mauris condimentum nibh. diff --git a/_announcements/2026-06-19-cras-mattis-consectetur.md b/_announcements/2026-06-19-cras-mattis-consectetur.md new file mode 100644 index 0000000..38fc3bf --- /dev/null +++ b/_announcements/2026-06-19-cras-mattis-consectetur.md @@ -0,0 +1,13 @@ +--- +title: Cras mattis consectetur purus sit amet +start: 2026-06-19 08:50:00 +end: 2026-06-19 09:25:00 +type: unplanned +services_affected: + - eln +summary: >- + Fermentum nibh, ut fermentum massa justo sit amet risus. +--- + +Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. +Morbi leo risus, porta ac consectetur ac, vestibulum at eros. diff --git a/_announcements/2026-07-08-vivamus-sagittis-lacus.md b/_announcements/2026-07-08-vivamus-sagittis-lacus.md new file mode 100644 index 0000000..ea8cd97 --- /dev/null +++ b/_announcements/2026-07-08-vivamus-sagittis-lacus.md @@ -0,0 +1,14 @@ +--- +title: Vivamus sagittis lacus vel augue laoreet +start: 2026-07-08 12:00:00 +end: 2026-07-08 14:00:00 +type: planned +services_affected: + - software-licenses +summary: >- + Rutrum faucibus dolor auctor, cras mattis consectetur purus sit amet + fermentum. +--- + +Aenean lacinia bibendum nulla sed consectetur. Etiam porta sem malesuada magna +mollis euismod, donec sed odio dui. diff --git a/_announcements/2026-07-30-donec-ullamcorper-nulla.md b/_announcements/2026-07-30-donec-ullamcorper-nulla.md new file mode 100644 index 0000000..46f0a0e --- /dev/null +++ b/_announcements/2026-07-30-donec-ullamcorper-nulla.md @@ -0,0 +1,13 @@ +--- +title: Donec ullamcorper nulla non metus auctor +start: 2026-07-30 10:40:00 +end: 2026-07-30 13:15:00 +type: unplanned +services_affected: + - data-deposition +summary: >- + Fringilla, duis mollis est non commodo luctus nisi erat porttitor ligula. +--- + +Curabitur blandit tempus porttitor. Vivamus sagittis lacus vel augue laoreet +rutrum faucibus dolor auctor, sed posuere consectetur est at lobortis. diff --git a/_announcements/2026-08-14-maecenas-sed-diam.md b/_announcements/2026-08-14-maecenas-sed-diam.md new file mode 100644 index 0000000..c7ad080 --- /dev/null +++ b/_announcements/2026-08-14-maecenas-sed-diam.md @@ -0,0 +1,16 @@ +--- +title: Maecenas sed diam eget risus varius +start: 2026-08-14 18:00:00 +end: 2026-08-15 02:00:00 +type: planned +services_affected: + - project-storage + - compute +summary: >- + Blandit sit amet non magna, curabitur blandit tempus porttitor. +--- + +Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Aenean eu +leo quam, pellentesque ornare sem lacinia quam venenatis vestibulum. + +Nullam quis risus eget urna mollis ornare vel eu leo. diff --git a/_announcements/2026-08-27-etiam-porta-sem.md b/_announcements/2026-08-27-etiam-porta-sem.md new file mode 100644 index 0000000..77cc473 --- /dev/null +++ b/_announcements/2026-08-27-etiam-porta-sem.md @@ -0,0 +1,18 @@ +--- +title: Etiam porta sem malesuada magna mollis +start: 2026-08-27 14:05:00 +end: 2026-08-27 17:20:00 +type: unplanned +services_affected: + - compute + - secure-compute +summary: >- + Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Nullam id dolor + id nibh ultricies. +--- + +Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id +ligula porta felis euismod semper. Sed posuere consectetur est at lobortis. + +Nulla vitae elit libero, a pharetra augue. Donec ullamcorper nulla non metus +auctor fringilla, duis mollis est non commodo luctus. diff --git a/_announcements/2026-09-05-integer-posuere-erat.md b/_announcements/2026-09-05-integer-posuere-erat.md new file mode 100644 index 0000000..d0fb62a --- /dev/null +++ b/_announcements/2026-09-05-integer-posuere-erat.md @@ -0,0 +1,16 @@ +--- +title: Integer posuere erat a ante venenatis +start: 2026-09-05 13:12:00 +end: 2026-09-05 13:54:00 +type: unplanned +services_affected: + - usegalaxy +summary: >- + Dapibus posuere velit aliquet, sed posuere consectetur est at lobortis. +--- + +Nullam quis risus eget urna mollis ornare vel eu leo. Cras mattis consectetur +purus sit amet fermentum, etiam porta sem malesuada magna mollis euismod. + +Aenean lacinia bibendum nulla sed consectetur, vivamus sagittis lacus vel augue +laoreet rutrum faucibus dolor auctor. diff --git a/_announcements/2026-09-12-fusce-dapibus-tellus.md b/_announcements/2026-09-12-fusce-dapibus-tellus.md new file mode 100644 index 0000000..72fa6b5 --- /dev/null +++ b/_announcements/2026-09-12-fusce-dapibus-tellus.md @@ -0,0 +1,14 @@ +--- +title: Fusce dapibus tellus in cursus commodo +start: 2026-09-12 07:00:00 +end: 2026-09-12 09:30:00 +type: planned +services_affected: + - data-transfer +summary: >- + Maecenas faucibus mollis interdum, morbi leo risus porta ac consectetur ac + vestibulum at eros. +--- + +Cum sociis natoque penatibus et magnis dis parturient montes, nascetur +ridiculus mus. Donec sed odio dui, nulla vitae elit libero a pharetra augue. diff --git a/_announcements/2026-09-19-lorem-ipsum-dolor-sit.md b/_announcements/2026-09-19-lorem-ipsum-dolor-sit.md new file mode 100644 index 0000000..427651d --- /dev/null +++ b/_announcements/2026-09-19-lorem-ipsum-dolor-sit.md @@ -0,0 +1,32 @@ +--- +title: Lorem ipsum dolor sit amet consectetur +start: 2026-09-19 09:30:00 +type: unplanned +services_affected: + - project-storage + - compute +summary: >- + Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim + ad minim veniam. +updates: + - time: 2026-09-20 11:00:00 + body: >- + Duis aute irure dolor in reprehenderit in voluptate velit esse cillum + dolore eu fugiat nulla pariatur. + - time: 2026-09-19 10:15:00 + body: >- + Quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. +--- + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor +incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis +nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +**Nam libero tempore** + +- Duis aute irure dolor in reprehenderit in voluptate velit esse cillum. +- Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia. + +Deserunt mollit anim id est laborum. Curabitur pretium tincidunt lacus, nulla +gravida orci a odio. diff --git a/_announcements/2026-10-06-nullam-varius-turpis.md b/_announcements/2026-10-06-nullam-varius-turpis.md new file mode 100644 index 0000000..c69c000 --- /dev/null +++ b/_announcements/2026-10-06-nullam-varius-turpis.md @@ -0,0 +1,24 @@ +--- +title: Nullam varius turpis et commodo pharetra +start: 2026-10-06 19:00:00 +end: 2026-10-06 23:00:00 +type: planned +services_affected: + - eln +summary: >- + Aenean ultricies mi vitae est mauris placerat eleifend leo quisque sit amet + est et sapien. +--- + +Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere +cubilia curae. Donec velit neque, auctor sit amet aliquam vel, ullamcorper sit +amet ligula. + +**Praesent sapien massa** + +- Convallis a pellentesque nec, egestas non nisi. +- Cras ultricies ligula sed magna dictum porta. +- Vivamus suscipit tortor eget felis porttitor volutpat. + +Nulla porttitor accumsan tincidunt. Quisque velit nisi, pretium ut lacinia in, +elementum id enim. diff --git a/_announcements/TEMPLATE.md b/_announcements/TEMPLATE.md new file mode 100644 index 0000000..428ca37 --- /dev/null +++ b/_announcements/TEMPLATE.md @@ -0,0 +1,25 @@ +--- +# Copy this file to YYYY-MM-DD-short-slug.md and edit it. This file itself is +# never rendered: _config.yml excludes it from the build. +title: Short sentence describing what people notice +start: 2026-09-19 09:30:00 +# Belgian local time. No timezone offset - do not write +02:00. +# end: 2026-09-19 18:00:00 +# Leave `end` out entirely while it is still going on. Add it once it is +# over and the entry moves to /history/ by itself. +type: unplanned +# unplanned | planned - see _data/levels.yml +services_affected: + - project-storage +# One or more ids from _data/services.yml +summary: >- + One or two sentences shown on the card and in the history. +# updates: +# - time: 2026-09-19 14:00:00 +# body: >- +# What changed since this went up. Every update is labelled "Update"; +# there is nothing else to set. +--- + +What people notice, and what they can do in the meantime. Normal Markdown: +**bold**, lists, `code`. diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..605db06 --- /dev/null +++ b/_config.yml @@ -0,0 +1,61 @@ +# --- Site ------------------------------------------------------------------- +title: VIB Data Core Announcements +tagline: Announcements on maintenance and disruptions of Data Core services +description: >- + Announcements on maintenance and disruptions of Data Core services. + +url: "https://vib-data-core.github.io" +baseurl: "/status" + +org: + name: "VIB Data Core" + +lang: en +timezone: Europe/Brussels + +# --- Content ---------------------------------------------------------------- +# One collection: everything on this site is an announcement. There is +# deliberately no "incident" type and no severity scale - see the README. +collections: + announcements: + output: true + permalink: /:name/ + +defaults: + - scope: + path: "" + type: announcements + values: + layout: entry + +# --- Build ------------------------------------------------------------------ +# Planned work is dated in the future by definition; without this Jekyll +# refuses to write those pages (default: future: false). +future: true + +markdown: kramdown +kramdown: + input: GFM + syntax_highlighter: rouge + +# No jekyll-sitemap: the site asks not to be indexed (see robots.txt and the +# robots meta tag in _includes/head.html), so a sitemap would contradict it. +plugins: [] + +sass: + style: compressed + +exclude: + - .github/ + # The announcement template is meant to be copied, not published. + - _announcements/TEMPLATE.md + - Gemfile + - Gemfile.lock + - LICENSE + - README.md + - node_modules/ + - package-lock.json + - package.json + - script/ + - vendor/ + - assets/css/tailwind.css # Tailwind input; the compiled file is assets/css/main.css \ No newline at end of file diff --git a/_data/levels.yml b/_data/levels.yml new file mode 100644 index 0000000..9d08ade --- /dev/null +++ b/_data/levels.yml @@ -0,0 +1,29 @@ +# The one controlled vocabulary of this site: the `type:` of an announcement. +# +# _announcements/*.md -> type: unplanned | planned +# +# There are only two, and there is deliberately no severity scale. Everything +# published here is an announcement written by hand by a Data Core member; a +# graded severity would suggest the page is fed by a monitoring system. +# +# `color` is the only colour setting for the whole site. Each entry carries it +# as the CSS variable --accent, and assets/css/tailwind.css derives the rest +# from that: the colour as given for the bar down the side of a card and the +# dot on the timeline, the same hue at lightness 0.95 with a quarter of the +# chroma for the badge fill, and lightness 0.43 with slightly more chroma for +# the badge label. Keep the colours light and lightly saturated - a strong, +# fully saturated hue reads as harsh next to the slate greys of the rest of the +# page, and a very light or very dark one pushes the derived label below the +# contrast it needs to stay readable. + +unplanned: + label: Unplanned + color: "#cf8f9c" + icon: circle-alert + description: Something is not working as it should, outside of planned work. + +planned: + label: Planned + color: "#8fb0cb" + icon: calendar-days + description: Work we have scheduled in advance. diff --git a/_data/services.yml b/_data/services.yml new file mode 100644 index 0000000..71c1af8 --- /dev/null +++ b/_data/services.yml @@ -0,0 +1,50 @@ +# Controlled vocabulary for the `services_affected:` front matter field. +# +# These are the VIB Data Core services as listed in the Data Core catalogue +# (the ones shown in Connect). Use the `id` in front matter, e.g. +# services_affected: [project-storage, usegalaxy] +# +# One announcement can cover several services. Adding a service = adding an +# entry here; script/validate.rb (and the check on every pull request) rejects +# ids that are not listed below. Ids are lowercase with dashes and should not +# change afterwards - they appear in shareable filter links such as +# ?services=usegalaxy,compute +# +# The descriptions below are placeholders and only surface as the tooltip on a +# service chip; replace them with the catalogue wording. + +- id: compute + name: Compute + description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +- id: secure-compute + name: Secure Compute + description: Sed do eiusmod tempor incididunt ut labore et dolore magna. + +- id: usegalaxy + name: useGalaxy.be + description: Ut enim ad minim veniam, quis nostrud exercitation ullamco. + +- id: project-storage + name: Project Storage + description: Laboris nisi ut aliquip ex ea commodo consequat. + +- id: eln + name: Electronic Lab Notebook + description: Duis aute irure dolor in reprehenderit in voluptate velit. + +- id: software-licenses + name: Scientific Software licenses + description: Esse cillum dolore eu fugiat nulla pariatur. + +- id: data-transfer + name: Data Transfer Solutions + description: Excepteur sint occaecat cupidatat non proident. + +- id: data-deposition + name: Data Deposition Toolbox + description: Sunt in culpa qui officia deserunt mollit anim id est laborum. + +- id: software-hosting + name: Software Hosting + description: Curabitur pretium tincidunt lacus, nulla gravida orci. diff --git a/_includes/entry-card.html b/_includes/entry-card.html new file mode 100644 index 0000000..cd5bfab --- /dev/null +++ b/_includes/entry-card.html @@ -0,0 +1,121 @@ +{%- comment -%} + One announcement, used in all three places: the "Current" and "Planned" + lists on the landing page and the timeline on /history/. The markup is + identical everywhere so assets/js/status.js can move an entry between the + lists when its start or end time passes, without the page being rebuilt. + + Params: + entry the announcement document + placement "current" | "planned" | "history" (initial placement only) + hide true to render it with the hidden attribute (history page, for + entries that have not closed yet) +{%- endcomment -%} + +{%- assign entry = include.entry -%} +{%- assign placement = include.placement | default: "history" -%} +{%- assign level_key = entry.type | default: "unplanned" -%} +{%- assign level = site.data.levels[level_key] -%} +{%- unless level -%}{%- assign level = site.data.levels.unplanned -%}{%- endunless -%} + +{%- if entry.end -%}{%- assign end_ts = entry.end | date: "%s" | plus: 0 -%}{%- else -%}{%- assign end_ts = 0 -%}{%- endif -%} + +{%- capture service_ids -%}{% for sid in entry.services_affected %}{{ sid }} {% endfor %}{%- endcapture -%} +{%- capture service_names -%}{% for sid in entry.services_affected %}{% assign svc = site.data.services | where: "id", sid | first %}{{ svc.name | default: sid }} {% endfor %}{%- endcapture -%} +{%- capture search_blob -%}{{ entry.title }} {{ entry.summary }} {{ level.label }} {{ service_ids }}{{ service_names }} {{ entry.content | strip_html }}{%- endcapture -%} + +{%- if placement == "current" -%}{%- assign state = "ongoing" -%} +{%- elsif placement == "planned" -%}{%- assign state = "scheduled" -%} +{%- else -%}{%- assign state = "closed" -%}{%- endif -%} + +
  • 0 %}data-end="{{ entry.end | date_to_xmlschema }}"{% endif %} + data-month="{{ entry.start | date: '%Y-%m' }}" + data-month-label="{{ entry.start | date: '%B %Y' }}" + data-search="{{ search_blob | strip_html | normalize_whitespace | truncate: 900, '' | downcase | escape }}"> + + + +
    + + {%- comment -%} + Just a dot in the colour of the type - the badge on the card already + carries the icon. It is opaque and ringed in the page colour, which is + what breaks the rail around it. Its centre sits 16px across and 30px + down, which is what the .entry-rail rules in tailwind.css measure from. + {%- endcomment -%} + + +
    + + +
    +
    + {%- comment -%} + No state pill on a card: the "Current" and "Planned" headings on the + landing page already say the state, and everything on the history + page is closed by definition. Only the type badge earns its space. + {%- endcomment -%} +

    + {%- include level-badge.html level=level_key -%} +

    + +

    + {{ entry.title }} +

    +
    +
    + + {%- if entry.summary %} +

    {{ entry.summary | strip_newlines }}

    + {%- endif %} + +
    +
    + {%- include icon.html name="clock" class="h-3.5 w-3.5 shrink-0 opacity-70" -%} +
    {% if placement == "planned" %}Starts{% else %}Started{% endif %}
    +
    + +
    +
    + +
    + {%- include icon.html name="hourglass" class="h-3.5 w-3.5 shrink-0 opacity-70" -%} +
    {% if placement == "history" %}Ended{% else %}Expected until{% endif %}
    +
    + +
    +
    +
    + + {%- if entry.updates and entry.updates.size > 0 -%} + {%- assign latest = entry.updates | sort: "time" | reverse | first -%} +
    +

    + + Update + +

    +

    {{ latest.body | strip_newlines }}

    +
    + {%- endif -%} + + +
    +
    +
  • diff --git a/_includes/footer.html b/_includes/footer.html new file mode 100644 index 0000000..98d2e1a --- /dev/null +++ b/_includes/footer.html @@ -0,0 +1,18 @@ +{%- comment -%} + Deliberately link-free: no repository, no support address, no documentation. + The page is a notice board and nothing more. +{%- endcomment -%} + diff --git a/_includes/head.html b/_includes/head.html new file mode 100644 index 0000000..d9c2a1c --- /dev/null +++ b/_includes/head.html @@ -0,0 +1,27 @@ + + + + + +{%- if page.title -%} + {%- assign page_title = page.title | append: " · " | append: site.title -%} +{%- else -%} + {%- assign page_title = site.title -%} +{%- endif -%} +{%- assign page_description = page.summary | default: page.description | default: site.description | strip_newlines | truncate: 200 -%} + +{{ page_title | escape }} + + + + + + + + + + + + + + diff --git a/_includes/icon.html b/_includes/icon.html new file mode 100644 index 0000000..4f68497 --- /dev/null +++ b/_includes/icon.html @@ -0,0 +1,40 @@ +{%- comment -%} + Inline Lucide icons (https://lucide.dev) - ISC licensed. + Usage: {% include icon.html name="triangle-alert" class="h-4 w-4" %} + To add one: copy the inner markup of the icon from lucide.dev into a new `when` branch. +{%- endcomment -%} +{%- assign icon_class = include.class | default: "h-5 w-5" -%} + diff --git a/_includes/level-badge.html b/_includes/level-badge.html new file mode 100644 index 0000000..db9c411 --- /dev/null +++ b/_includes/level-badge.html @@ -0,0 +1,11 @@ +{%- comment -%} + Badge for the type of an announcement. + Params: level (key from _data/levels.yml) +{%- endcomment -%} +{%- assign level_key = include.level | default: "info" -%} +{%- assign level = site.data.levels[level_key] -%} +{%- unless level -%}{%- assign level = site.data.levels.info -%}{%- endunless -%} + + {%- include icon.html name=level.icon class="h-3.5 w-3.5" -%} + {{ level.label }} + diff --git a/_includes/service-tags.html b/_includes/service-tags.html new file mode 100644 index 0000000..5027a28 --- /dev/null +++ b/_includes/service-tags.html @@ -0,0 +1,34 @@ +{%- comment -%} + Clickable service tags. On the history page JS intercepts the click and adds + the service to the active filter set; anywhere else (and without JS) the + link simply navigates to the filtered history. + + Params: + entry + surface "card" (default) for tags on a white or tinted card, "page" for + tags sitting straight on the page background - a slate-100 tag + would be invisible there, so those go white instead. +{%- endcomment -%} +{%- assign entry = include.entry -%} +{%- if include.surface == "page" -%} + {%- assign tag_fill = "bg-white hover:bg-slate-200" -%} +{%- else -%} + {%- assign tag_fill = "bg-slate-100 hover:bg-slate-200" -%} +{%- endif -%} +{%- if entry.services_affected and entry.services_affected.size > 0 -%} + +{%- endif -%} diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 0000000..46ee50e --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,21 @@ + + + + {%- include head.html -%} + + + + Skip to content + + + {%- comment -%}No top bar at all: the pages carry their own heading.{%- endcomment -%} +
    + {{ content }} +
    + + {%- include footer.html -%} + + + + diff --git a/_layouts/entry.html b/_layouts/entry.html new file mode 100644 index 0000000..da899ce --- /dev/null +++ b/_layouts/entry.html @@ -0,0 +1,145 @@ +--- +layout: default +--- + +{%- assign level_key = page.type | default: "unplanned" -%} +{%- assign level = site.data.levels[level_key] -%} +{%- unless level -%}{%- assign level = site.data.levels.unplanned -%}{%- endunless -%} + +{%- assign now_ts = site.time | date: "%s" | plus: 0 -%} +{%- assign start_ts = page.start | date: "%s" | plus: 0 -%} +{%- if page.end -%}{%- assign end_ts = page.end | date: "%s" | plus: 0 -%}{%- else -%}{%- assign end_ts = 0 -%}{%- endif -%} + +{%- if end_ts > 0 and end_ts <= now_ts -%} + {%- assign state = "closed" -%} +{%- elsif start_ts > now_ts -%} + {%- assign state = "scheduled" -%} +{%- else -%} + {%- assign state = "ongoing" -%} +{%- endif -%} + +
    0 %}data-end="{{ page.end | date_to_xmlschema }}"{% endif %}> + +
    + + +
    + + {%- include icon.html name="arrow-left" class="h-4 w-4" -%} + Back to Home + + + {%- comment -%} + No level icon here: the coloured bar at the top of the header and the + level badge below already carry it, and dropping it lets the title + start at the left margin. + {%- endcomment -%} +
    +{%- comment -%} + No state pill: the coloured rule at the top of the header, the badge + and the Start / End panel below already say where this + announcement stands. + {%- endcomment -%} + {%- include level-badge.html level=level_key -%} + +

    {{ page.title }}

    + + {%- if page.summary %} +

    {{ page.summary | strip_newlines }}

    + {%- endif %} +
    +
    +
    + +
    + +
    +
    +
    + {%- include icon.html name="clock" class="h-3.5 w-3.5" -%} + Start +
    +
    + +
    +
    + +
    +
    + {%- include icon.html name="hourglass" class="h-3.5 w-3.5" -%} + End +
    +
    + {%- if end_ts > 0 -%} + + expected + {%- else -%} + Still open + {%- endif -%} +
    +
    +
    + + {%- if page.services_affected and page.services_affected.size > 0 %} +
    +

    Services affected

    +
    + {%- include service-tags.html entry=page surface="page" -%} +
    +
    + {%- endif %} + + {%- if page.updates and page.updates.size > 0 %} +
    +

    Updates

    + {%- comment -%} + Same thread-and-dot as the history timeline: each update draws its own + piece of the rail, and the rules in tailwind.css trim the first and the + last so the line runs dot to dot instead of past both ends. + {%- endcomment -%} +
    +
      + {%- assign sorted_updates = page.updates | sort: "time" | reverse -%} + {%- for u in sorted_updates %} +
    1. + + +
      +

      + Update + +

      +

      {{ u.body | strip_newlines }}

      +
      +
    2. + {%- endfor %} +
    +
    +
    + {%- endif %} + +
    + {{ content }} +
    + + +
    +
    diff --git a/_plugins/local_times.rb b/_plugins/local_times.rb new file mode 100644 index 0000000..5d82190 --- /dev/null +++ b/_plugins/local_times.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +# Every time on this site is Belgian local time. Announcements are written by +# hand, and "2026-09-19 09:30:00 +02:00" is a lot of ceremony - and a DST trap +# twice a year - for someone who just wants to say half past nine. +# +# YAML reads a timestamp without an offset as UTC. Left alone, Jekyll then +# renders a bare "09:30" as 09:30 in the visible text but as 11:30+02:00 in the +#