diff --git a/.gitignore b/.gitignore index d680206..91408b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.sif *.tar +*.DS_Store +slides.* \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 6feb718..ac15cd0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,6 +25,8 @@ RUN cd /slidefactory && \ FROM docker.io/debian:bookworm +ARG INCLUDE_ILLUSTRATIONS=true + ENV DEBIAN_FRONTEND=noninteractive # General packages @@ -55,11 +57,11 @@ RUN apt-get update -qy && \ apt-get clean # Fonts -RUN FONT_DIR=NotoSans && \ +RUN FONT_DIR=NunitoSans && \ mkdir -p /slidefactory/fonts/$FONT_DIR && \ - wget https://github.com/notofonts/latin-greek-cyrillic/releases/download/NotoSans-v2.013/NotoSans-v2.013.zip -O tmp.zip && \ - unzip -j tmp.zip 'NotoSans/googlefonts/ttf/*' -d /slidefactory/fonts/$FONT_DIR && \ - unzip -j tmp.zip 'OFL.txt' -d /slidefactory/fonts/$FONT_DIR && \ + wget https://github.com/googlefonts/NunitoSans/archive/refs/heads/main.zip -O tmp.zip && \ + unzip -j tmp.zip 'NunitoSans-main/fonts/ttf/*' -d /slidefactory/fonts/$FONT_DIR && \ + unzip -j tmp.zip 'NunitoSans-main/OFL.txt' -d /slidefactory/fonts/$FONT_DIR && \ rm tmp.zip RUN FONT_DIR=Inconsolata && \ @@ -69,6 +71,16 @@ RUN FONT_DIR=Inconsolata && \ unzip -j tmp.zip 'Inconsolata-3.000/OFL.txt' -d /slidefactory/fonts/$FONT_DIR && \ rm tmp.zip +# CSC brand illustrations (optional, set INCLUDE_ILLUSTRATIONS=false to skip) +RUN if [ "$INCLUDE_ILLUSTRATIONS" = "true" ]; then \ + mkdir -p /slidefactory/img/csc_illustrations && \ + wget https://a3s.fi/swift/v1/slides/csc_illustrations.zip -O tmp.zip && \ + unzip -j tmp.zip -d /slidefactory/img/csc_illustrations && \ + rm tmp.zip; \ + else \ + echo "Skipping CSC illustrations (INCLUDE_ILLUSTRATIONS=$INCLUDE_ILLUSTRATIONS)"; \ + fi + # Reveal.js RUN wget https://github.com/hakimel/reveal.js/archive/refs/tags/4.4.0.zip -O tmp.zip && \ unzip tmp.zip 'reveal.js-4.4.0/LICENSE' -d /slidefactory && \ @@ -86,7 +98,14 @@ RUN wget https://github.com/mathjax/MathJax/archive/refs/tags/3.2.2.zip -O tmp.z rm -f tmp.zip # Pandoc -RUN wget https://github.com/jgm/pandoc/releases/download/2.19.2/pandoc-2.19.2-1-amd64.deb -O tmp.deb && \ +RUN ARCH=$(dpkg --print-architecture) && \ + if [ "$ARCH" = "amd64" ]; then \ + wget https://github.com/jgm/pandoc/releases/download/3.8.2/pandoc-3.8.2-1-amd64.deb -O tmp.deb; \ + elif [ "$ARCH" = "arm64" ]; then \ + wget https://github.com/jgm/pandoc/releases/download/3.8.2/pandoc-3.8.2-1-arm64.deb -O tmp.deb; \ + else \ + echo "Unsupported architecture: $ARCH" && exit 1; \ + fi && \ dpkg -i tmp.deb && \ rm -f tmp.deb diff --git a/Makefile b/Makefile index 0c2c876..b2e9ffb 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,25 @@ IMAGE_ROOT?=ghcr.io/csc-training IMAGE=slidefactory -IMAGE_VERSION?=$(shell grep -m1 -oP '(?<=VERSION = ").+(?=")' slidefactory.py) - +IMAGE_VERSION=$(shell grep -m1 'VERSION = "' slidefactory.py | sed -E 's/.*VERSION = "(.*)".*/\1/') +CONTAINER_CMD=$(shell command -v podman >/dev/null 2>&1 && echo podman || echo docker) +INCLUDE_ILLUSTRATIONS?=true build: Dockerfile slidefactory.py - docker build \ + ${CONTAINER_CMD} build \ + --platform "linux/amd64,linux/arm64" \ --label "org.opencontainers.image.source=https://github.com/csc-training/slidefactory" \ --label "org.opencontainers.image.description=slidefactory" \ --build-arg VERSION=${IMAGE_VERSION} \ + --build-arg INCLUDE_ILLUSTRATIONS=${INCLUDE_ILLUSTRATIONS} \ -t ${IMAGE_ROOT}/${IMAGE}:${IMAGE_VERSION} \ . push: - docker push ${IMAGE_ROOT}/${IMAGE}:${IMAGE_VERSION} + ${CONTAINER_CMD} push ${IMAGE_ROOT}/${IMAGE}:${IMAGE_VERSION} singularity: rm -f $(IMAGE).sif $(IMAGE).tar - docker save $(IMAGE_ROOT)/$(IMAGE):$(IMAGE_VERSION) -o $(IMAGE).tar + ${CONTAINER_CMD} save $(IMAGE_ROOT)/$(IMAGE):$(IMAGE_VERSION) -o $(IMAGE).tar singularity build $(IMAGE).sif docker-archive://$(IMAGE).tar rm -f $(IMAGE).tar diff --git a/README.md b/README.md index 8780bee..628f54b 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,52 @@ Use help for all other options: ./slidefactory_VERSION.sif slides --help +#### Themes + +Two themes are bundled: + +* `csc-2026` (default) - the current CSC brand: new color palette, the + `Nunito Sans` font, and support for the [CC license badge](#license) on + the title slide. +* `csc-old` - the previous CSC look (formerly named `csc-plain`), kept for + continuity with older material. + +Select a bundled theme by name by adding `--theme csc-old` with the run command. + + +#### Illustrations + +21 CSC brand illustrations (`CSC_Characters_01.png` - `CSC_Characters_21.png`) +are available for use in slides. They are not stored in this repository - +instead they are downloaded from an external source and bundled into the +container image at build time (see `Dockerfile`), the same way fonts and +reveal.js are handled. Reference them in `slides.md` by filename, without +needing to know where slidefactory is installed: + +  + +Including the illustrations in the image is optional. They are included by +default; skip them with: + + make build INCLUDE_ILLUSTRATIONS=false + + +#### License + +Add a `license` key to the YAML metadata block at the top of `slides.md` +to display a Creative Commons badge and link on the title slide (theme +`csc-2026` only): + + --- + title: My Slides + license: by + --- + +Valid values are the standard CC 4.0 license slugs: `by`, `by-sa`, `by-nd`, +`by-nc`, `by-nc-sa`, `by-nc-nd`. If `license` is left out, no license +information is shown. + + #### Build pages for a project Use pages sub-command to create an index page and convert all slides: @@ -69,16 +115,19 @@ and follow the instructions. ### Docker / podman +The commands below work identically with `docker` or `podman` - just swap +the binary name. + Fetch the slidefactory container image: - docker pull ghcr.io/csc-training/slidefactory:VERSION + docker/podman pull ghcr.io/csc-training/slidefactory:VERSION Convert the markdown slides to a PDF (default): - docker run -it --rm -v "$PWD:$PWD:Z" -w "$PWD" ghcr.io/csc-training/slidefactory:VERSION slides --format pdf slides.md + docker/podman run -it --rm -v "$PWD:$PWD:Z" -w "$PWD" ghcr.io/csc-training/slidefactory:VERSION slides --format pdf slides.md All the options work the same way as for singularity -but using the above docker command instead. +but using the above docker/podman command instead. ## Known issues diff --git a/fonts/fonts.css b/fonts/fonts.css index f431b27..397f834 100644 --- a/fonts/fonts.css +++ b/fonts/fonts.css @@ -1,33 +1,33 @@ @font-face { - font-family: 'Noto Sans'; + font-family: 'Nunito Sans'; font-style: normal; font-weight: 400; font-stretch: 100%; - src: url(NotoSans/NotoSans-Regular.ttf) format(truetype); + src: url(NunitoSans/NunitoSans-Regular.ttf) format(truetype); } @font-face { - font-family: 'Noto Sans'; + font-family: 'Nunito Sans'; font-style: normal; font-weight: 700; font-stretch: 100%; - src: url(NotoSans/NotoSans-Bold.ttf) format(truetype); + src: url(NunitoSans/NunitoSans-Bold.ttf) format(truetype); } @font-face { - font-family: 'Noto Sans'; + font-family: 'Nunito Sans'; font-style: italic; font-weight: 400; font-stretch: 100%; - src: url(NotoSans/NotoSans-Italic.ttf) format(truetype); + src: url(NunitoSans/NunitoSans-Italic.ttf) format(truetype); } @font-face { - font-family: 'Noto Sans'; + font-family: 'Nunito Sans'; font-style: italic; font-weight: 700; font-stretch: 100%; - src: url(NotoSans/NotoSans-BoldItalic.ttf) format(truetype); + src: url(NunitoSans/NunitoSans-BoldItalic.ttf) format(truetype); } @font-face { diff --git a/slidefactory.py b/slidefactory.py index d4b19d1..29f12e8 100755 --- a/slidefactory.py +++ b/slidefactory.py @@ -28,6 +28,7 @@ VERSION = "3.4.3" SLIDEFACTORY_ROOT = Path(__file__).absolute().parent IN_CONTAINER = SLIDEFACTORY_ROOT == Path('/slidefactory') +SHARED_IMG_DPATH = SLIDEFACTORY_ROOT / 'img' # Modify version string if this file has been edited with open(__file__, 'rb') as f: @@ -451,7 +452,7 @@ def main(): pparser_conversion = argparse.ArgumentParser(add_help=False) pparser_conversion.add_argument( '-t', '--theme', metavar='THEME', type=find_theme, - default='csc-plain', + default='csc-2026', help='presentation theme name or path (default: %(default)s)') pparser_conversion.add_argument( '--filters', action='append', default=[], @@ -596,6 +597,10 @@ def main_slides(args): pandoc_args += ['--mathjax'] if args.format in ['html-embedded']: pandoc_args += ['--embed-resources'] + if SHARED_IMG_DPATH.is_dir(): + # Let authors reference images from the shared img/ folder by + # filename only, without knowing where slidefactory is installed + pandoc_args += [f'--resource-path=.:{SHARED_IMG_DPATH}'] # Convert files for in_fpath in args.input: @@ -611,20 +616,26 @@ def main_slides(args): defaults_fpath=args.defaults_fpath, template_fpath=args.template_fpath, pandoc_vars=pandoc_vars, - pandoc_args=pandoc_args, filters=args.filters, dry_run=args.dry_run, ) if args.format == 'pdf': - # Use temporary html output for pdf + # Use temporary html output for pdf, and a temporary dir to + # resolve/copy any resource-path images used in the input with tempfile.NamedTemporaryFile( dir=in_fpath.parent, prefix=f'{in_fpath.stem}-', suffix='.html', - ) as tmpfile: + ) as tmpfile, \ + tempfile.TemporaryDirectory( + dir=in_fpath.parent, + prefix=f'{in_fpath.stem}-media-', + ) as media_dpath: html_fpath = Path(tmpfile.name) - create_html(in_fpath, html_fpath, **html_kwargs) + create_html(in_fpath, html_fpath, + pandoc_args=pandoc_args + [f'--extract-media={media_dpath}'], # noqa: E501 + **html_kwargs) meta = read_slides_metadata(in_fpath) # Use event name as subject if no separate subject defined @@ -632,8 +643,16 @@ def main_slides(args): meta['subject'] = meta['event'] create_pdf(html_fpath, out_fpath, meta=meta, dry_run=args.dry_run) + elif args.format == 'html-embedded': + # --embed-resources already inlines resolved images; no + # separate media directory needed + create_html(in_fpath, out_fpath, pandoc_args=pandoc_args, + **html_kwargs) else: - create_html(in_fpath, out_fpath, **html_kwargs) + media_dpath = out_fpath.parent / f'{out_fpath.stem}_media' + create_html(in_fpath, out_fpath, + pandoc_args=pandoc_args + [f'--extract-media={media_dpath}'], # noqa: E501 + **html_kwargs) def main_pages(args): diff --git a/theme/csc-2026/csc.css b/theme/csc-2026/csc.css new file mode 100644 index 0000000..bf6b32b --- /dev/null +++ b/theme/csc-2026/csc.css @@ -0,0 +1,641 @@ +/* CSC colors from design guide */ + +:root { + --csc-text-dark: #002930; + --csc-text-light: #ffffff; + --csc-bg-light-peach: #fff8f5; + --csc-bg-peach: #ffeee5; + --csc-bg-light-grey: #eff0f1; + --csc-bg-grey: #dfe1e3; + --csc-dark-green: #005260; + --csc-mid-green: #B0DCBA; + --csc-light-green: #DBEEE0; + --csc-highlight-green: #4EA663; + --csc-dark-blue: #02284F; + --csc-mid-blue: #ABCFEF; + --csc-light-blue: #C8E0F5; + --csc-highlight-blue: #0075D6; + --csc-dark-red: #830051; + --csc-mid-red: #F1CCD7; + --csc-light-red: #F8EAE9; + --csc-highlight-red: #FF5800; + +} + +/* Screen geometry + base size for text */ +:root { + --xsize: 1920px; + --ysize: 1080px; + --xmargin: 74px; + --ymargin: 84px; + --fontsize: 50px; +} +/* Fonts */ +:root { + --csc-font-family: 'Nunito Sans'; + --csc-code-font-family: 'Inconsolata'; +} + +/********************************************* + * GLOBAL STYLES + *********************************************/ +.reveal-viewport { + background-color: black; +} + +.slide-background { + background-image: url("img/normal.svg"); + background-repeat: no-repeat; + background-position: center; + background-size: contain; +} + +.slide-background.title { + background-image: url("img/title.svg"); +} + +:lang(fi) .slide-background.title { + background-image: url("img/title.svg"); +} + +.slide-background.section { + background-image: url("img/normal.svg"); +} + +.slide-background.author { + background-image: url("img/author.svg"); +} + +.high-contrast .reveal { + color: var(--csc-text-dark);; +} +.reveal { + font-family: var(--csc-font-family); + font-size: var(--fontsize); + color: var(--csc-text-dark); + font-weight: normal; +} +.reveal .slide-number, +html.print-pdf .reveal .slide-number { + font-family: var(--csc-font-family); + font-size: 30px; + color: var(--csc-text-dark); + font-weight: normal; + left: calc(0.3 * var(--xmargin)); + right: auto; + bottom: calc(0.3 * var(--ymargin)); + background-color: transparent; +} +.reveal .slides { + text-align: left; + line-height: 1.4; +} +.reveal .slides section.slide , +.reveal .slides .pdf-page section.slide { + margin-top: var(--ymargin) !important; + margin-left: var(--xmargin) !important; + margin-right: var(--xmargin) !important; + max-width: calc(var(--xsize) - 2 * var(--xmargin)) !important; + padding: 0 !important; +} +.reveal p { + margin-top: 1ex; +} +.reveal section.slide::before { + content: ""; +} +.reveal .text-green { + color: var(--csc-highlight-green); +} +.reveal .text-blue { + color: var(--csc-highlight-blue); +} +.reveal .text-red { + color: var(--csc-highlight-red); +} +.reveal .text-ghost { + color: transparent; +} +.reveal .bg-light-peach { + background-color: var(--csc-bg-light-peach); +} +.reveal .bg-peach { + background-color: var(--csc-bg-peach); +} +.reveal .bg-light-grey { + background-color: var(--csc-bg-light-grey); +} +.reveal .bg-grey { + background-color: var(--csc-bg-grey); +} + +/********************************************* + * HEADERS + *********************************************/ +.reveal h1, .reveal h2, .reveal h3 { + line-height: 1.1; + text-align: left; + font-weight: bold; +} +.reveal h1 { + font-size: 1.2em; + color: var(--csc-text-dark); +} +.reveal h2 { + font-size: 1.1em; + padding-top: 1ex; + padding-bottom: 1ex; +} +.reveal h3 { + font-size: 1em; + padding-top: 1ex; +} +.reveal section.slide h1:first-child { + padding-bottom: 1.7em; +} +.reveal section.slide h2:first-child, +.reveal section.slide h3:first-child, +.reveal section.slide h1:first-child + p, +.reveal section.slide h1:first-child + h2, +.reveal section.slide h1:first-child + h3, +.reveal .column p:first-child, +.reveal .column h2:first-child, +.reveal .column h3:first-child { + padding-top: 0; + margin-top: 0; +} + +/********************************************* + * OTHER + *********************************************/ + +/* Ensure certain elements are never larger than the slide itself */ +.reveal img, +.reveal video, +.reveal iframe { + max-width: 95%; + max-height: 95%; +} + +/* General formatting */ +.reveal strong, b { + font-weight: bold; +} +.reveal em { + font-style: italic; +} +.reveal sup { + vertical-align: super; +} +.reveal sub { + vertical-align: sub; +} +.reveal small { + font-size: 0.7em; +} + +/********************************************* + * DOUBLE COLUMN LAYOUT + *********************************************/ +.reveal .column { + width: 49%; +} +.reveal .column:first-of-type { + float: left; + margin-right: 1%; +} +.reveal .column:last-of-type { + float: right; + margin-left: 1%; +} +.reveal .column:first-of-type ul, +.reveal .column:first-of-type ol, +.reveal .column:first-of-type dl, +.reveal .column:first-of-type p, +.reveal .column:first-of-type h2, +.reveal .column:first-of-type h3, +.reveal .column:first-of-type pre, +.reveal .column:first-of-type table, +.reveal .column:first-of-type figure, +.reveal .column:first-of-type video { + margin-right: 0; +} +.reveal .column:last-of-type ul, +.reveal .column:last-of-type ol, +.reveal .column:last-of-type dl, +.reveal .column:last-of-type p, +.reveal .column:last-of-type h2, +.reveal .column:last-of-type h3, +.reveal .column:last-of-type pre, +.reveal .column:last-of-type table, +.reveal .column:last-of-type figure, +.reveal .column:last-of-type video { + margin-left: 0; +} + +/********************************************* + * LISTS + *********************************************/ +.reveal ol, +.reveal dl, +.reveal ul { + display: inline-block; +} +.reveal ol { + list-style-type: decimal; +} +.reveal ul { + list-style-type: disc; +} +.reveal ul ul { + list-style-type: circle; +} +.reveal li { + margin-left: 1em; + margin-right: 0; + margin-bottom: 1ex; +} + +.reveal ul ul, +.reveal ul ol, +.reveal ol ol, +.reveal ol ul, +.reveal ul dl, +.reveal ol dl { + display: block; + margin-left: 0.5em; +} +.reveal li li { + font-size: 0.9em; + margin-bottom: 0; +} +.reveal li p { + margin-left: 0; +} + +/* description list */ +.reveal dt { + margin-top: 1ex; + font-family: var(--csc-code-font-family); + font-weight: bold; +} +.reveal dt:first-child, +.reveal dl dl dt { + margin-top: 0; +} +.reveal dd { + margin-left: 1em; +} +.reveal dd dl { + margin-left: 0; + margin-right: 0; +} +.reveal ul dl dd, +.reveal ol dl dd, +.reveal dd dl dd { + font-size: 0.8em; +} +.reveal dl p:first-child { + margin-top: 0; +} +.reveal dd p { + margin-left: 0; +} +.reveal .split-definition dd dl, +.reveal .split-def-2 dd dl { + column-count: 2; + column-width: calc(0.5 * (var(--xsize) - 2 * var(--xmargin)) - 1em); +} +.reveal .split-def-3 dd dl { + column-count: 3; + column-width: calc(0.33 * (var(--xsize) - 2 * var(--xmargin)) - 1em); +} +.reveal .split-def-3 dd dl dt { + font-size: 0.9em; +} +.reveal .split-def-3 dd dl dd { + font-size: 0.7em; +} + + +/********************************************* + * CODE + *********************************************/ +.reveal div.sourceCode { + margin-top: 0.1em; + margin-bottom: 0.1em; +} +.reveal pre { + display: block; + margin-top: 2px; + margin-bottom: 1ex; + font-size: 0.7em; + line-height: 1.2; + word-wrap: break-word; + border: 2px solid; +} +.reveal pre, +.reveal code, +.reveal code.sourceCode, +.reveal code.sourceCode > span { + font-family: var(--csc-code-font-family); + color: var(--csc-text-dark); +} +.reveal pre code { + display: block; + padding: 5px; + overflow: auto; + max-height: calc(0.735 * var(--ysize)); + word-wrap: normal; + white-space: pre; + font-family: var(--csc-code-font-family); +} +.reveal code { + white-space: pre-wrap; +} +.reveal p code { + padding-left: 0.1em; + padding-right: 0.1em; +} +.reveal code.input { + color: var(--csc-highlight-red); +} +.reveal code.output { + color: var(--csc-highlight-green); +} +.reveal code.ghost { + color: transparent; +} +.reveal mark { + background-color: var(--csc-highlight-blue); +} + +/********************************************* + * TABLES + *********************************************/ +.reveal table { + margin-bottom: 1ex; + border-collapse: collapse; + border-spacing: 0; +} +.reveal table th { + font-weight: bold; +} +.reveal table th, +.reveal table td { + padding: 0.2em 0.5em 0.2em 0.5em; +} +.reveal table th[align="center"], +.reveal table td[align="center"] { + text-align: center; +} +.reveal table th[align="right"], +.reveal table td[align="right"] { + text-align: right; +} +.reveal table th[align="left"], +.reveal table td[align="left"] { + text-align: left; +} +/* cell highlight */ +.reveal table strong em, +.reveal table b em { + color: var(--csc-highlight-red); + font-style: normal; + font-weight: normal; +} +/* default style w/ only some horisontal lines */ +.reveal table thead { + border-top: 4px solid; + border-bottom: 2px solid; +} +.reveal table tbody { + border-bottom: 4px solid; +} +/* alternative style w/ color accents */ +.reveal .table-colour table th, +.reveal .table-colour table td:first-child { + color: var(--csc-highlight-blue); + font-weight: normal; +} +.reveal .table-colour table strong, b { + color: var(--csc-highlight-blue); + font-weight: normal; +} +/* alternative style w/ visible cells in colour */ +.reveal .table-grid table { + border-collapse: separate; + border-spacing: 0.1ex; +} +.reveal .table-grid table th, +.reveal .table-grid table td { + padding: 0.1em 0.5em 0.1em 0.5em; + background-color: var(--csc-light-blue); + color: var(--csc-text-dark); +} +.reveal .table-grid table thead, +.reveal .table-grid table tbody { + border: none; +} +/* alternative style w/out any extra styling */ +.reveal .table-none table thead, +.reveal .table-none table tbody { + border: none; +} +.reveal .table-none table th { + font-weight: normal; +} +.reveal .table-none table strong em, +.reveal .table-none table b em { + color: var(--csc-text-dark); + font-style: italic; + font-weight: bold; +} + +/********************************************* + * LINKS + *********************************************/ +.reveal a { + color: var(--csc-dark-blue); + text-decoration: none; + -webkit-transition: color .15s ease; + -moz-transition: color .15s ease; + transition: color .15s ease; } + +.reveal a:hover { + color: var(--csc-mid-blue); + text-shadow: none; + border: none; } + +.reveal .roll span:after { + color: #fff; + background: var(--csc-dark-blue); } + +/********************************************* + * IMAGES + *********************************************/ +.reveal section img { + border: 0; + box-shadow: none; +} +.reveal section img.border { + border: 4px solid #222; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); +} +.reveal section img.center { + margin-left: auto; + margin-right: auto; + display: block; +} + +.reveal a img { + -webkit-transition: all .15s linear; + -moz-transition: all .15s linear; + transition: all .15s linear; +} +.reveal a:hover img { + background: rgba(255, 255, 255, 0.2); + border-color: #2a76dd; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); +} + +/********************************************* + * NAVIGATION CONTROLS + *********************************************/ +.reveal .controls .navigate-left, +.reveal .controls .navigate-left.enabled { + border-right-color: var(--csc-mid-blue); } + +.reveal .controls .navigate-right, +.reveal .controls .navigate-right.enabled { + border-left-color: var(--csc-mid-blue); } + +.reveal .controls .navigate-up, +.reveal .controls .navigate-up.enabled { + border-bottom-color: var(--csc-mid-blue); } + +.reveal .controls .navigate-down, +.reveal .controls .navigate-down.enabled { + border-top-color: var(--csc-mid-blue); } + +.reveal .controls .navigate-left.enabled:hover { + border-right-color: var(--csc-light-blue); } + +.reveal .controls .navigate-right.enabled:hover { + border-left-color: var(--csc-light-blue); } + +.reveal .controls .navigate-up.enabled:hover { + border-bottom-color: var(--csc-light-blue); } + +.reveal .controls .navigate-down.enabled:hover { + border-top-color: var(--csc-light-blue); } + +/********************************************* + * PROGRESS BAR + *********************************************/ +.reveal .progress { + background: var(--csc-light-blue); +} +.reveal .progress span { + background: var(--csc-dark-blue); + -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); + -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); + transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); +} + +/********************************************* + * CSC SPECIAL SLIDES + *********************************************/ + +/* Title slide */ + +.reveal .slides section.slide.title , +.reveal .slides .pdf-page section.slide.title { + margin-top: calc(0.66 * var(--ysize)) !important; + margin-left: calc(0.12 * var(--xsize)) !important; + margin-right: 0 !important; + max-width: calc(0.64 * var(--xsize)) !important; +} +.reveal section.slide.title * { + color: var(--csc-text-dark); + text-align: left; +} +.reveal section.slide.title h1 { + transform: translateY(-100%); + font-size: 1.4em; + font-weight: bold; + line-height: 1.2; +} +.reveal section.slide.title p { + position: absolute; + left: 0.0em; + font-size: 0.6em; +} + +.reveal section.slide.title p.author { + top: -2.8em; +} +.reveal section.slide.title p.date { + top: -0.6em; +} +.reveal section.slide.title p.license { + left: calc(0.38 * var(--xsize)); + top: calc(0.22 * var(--ysize)); + transform: translateX(-50%); + display: flex; + align-items: center; + gap: 0.6em; + width: max-content; + max-width: calc(0.6 * var(--xsize)); +} +.reveal section.slide.title p.license img { + width: 160px; + height: auto; + flex-shrink: 0; +} +.reveal section.slide.title p.license .license-note { + font-size: 0.7em; + line-height: 1.3; + text-align: left; +} + +/* Section slide */ + +.reveal .slides section.slide.section , +.reveal .slides .pdf-page section.slide.section { + margin-top: calc(0.412 * var(--ysize)) !important; +} +.reveal section.slide.section h1:first-child { + padding-bottom: 1ex; +} +.reveal section.slide.section p { + font-size: 0.8em; +} + +/* Author slide */ + +.reveal .slides section.slide.author, +.reveal .slides .pdf-page section.slide.author { + margin-top: calc(0.58 * var(--ysize)) !important; + margin-left: calc(0.24 * var(--xsize)) !important; +} +.reveal section.slide.author { + text-align: left; + font-size: 0.5em; +} +.reveal section.slide.author h1, +.reveal section.slide.author div { + padding-bottom: 1.4em; +} +.reveal section.slide.author h1 { + font-weight: bold; +} +.reveal section.slide.author img { + position: absolute; + top: 0; + left: calc(-0.167 * var(--xsize)); + width: calc(0.142 * var(--xsize)); + max-width: unset; + max-height: unset; + border: 0; +} diff --git a/theme/csc-2026/defaults.yaml b/theme/csc-2026/defaults.yaml new file mode 100644 index 0000000..54a0acf --- /dev/null +++ b/theme/csc-2026/defaults.yaml @@ -0,0 +1,18 @@ +--- +standalone: true +from: markdown-native_divs +to: revealjs +variables: + width: 1920 + height: 1080 + history: true + center: false + controls: true + transition: none + backgroundTransition: none + slideNumber: true + showSlideNumber: all + progress: true +highlight-style: pygments +... +--- diff --git a/theme/csc-2026/img/author.svg b/theme/csc-2026/img/author.svg new file mode 100644 index 0000000..f974668 --- /dev/null +++ b/theme/csc-2026/img/author.svg @@ -0,0 +1,1023 @@ + + + + diff --git a/theme/csc-2026/img/normal.svg b/theme/csc-2026/img/normal.svg new file mode 100644 index 0000000..ae0db81 --- /dev/null +++ b/theme/csc-2026/img/normal.svg @@ -0,0 +1,39 @@ + + + + diff --git a/theme/csc-2026/img/title.svg b/theme/csc-2026/img/title.svg new file mode 100644 index 0000000..24da82a --- /dev/null +++ b/theme/csc-2026/img/title.svg @@ -0,0 +1,115 @@ + + + + diff --git a/theme/csc-2026/template.html b/theme/csc-2026/template.html new file mode 100644 index 0000000..0111489 --- /dev/null +++ b/theme/csc-2026/template.html @@ -0,0 +1,352 @@ + + +
+ + +$for(author-meta)$ + +$endfor$ +$if(date-meta)$ + +$endif$ +$if(keywords)$ + +$endif$ +