diff --git a/docs/cli/examples.md b/docs/cli/examples.md
index eb59a950..b7090474 100644
--- a/docs/cli/examples.md
+++ b/docs/cli/examples.md
@@ -7,7 +7,7 @@ This page contains practical examples of using the immichpy CLI for common tasks
Get all albums and their name and ID:
-
+
```console
$ immichpy albums get-all-albums | jq -r '.[] | "\(.album_name) \(.id)"'
diff --git a/docs/css/termynal.css b/docs/css/termynal.css
deleted file mode 100644
index 0602326a..00000000
--- a/docs/css/termynal.css
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * termynal.js
- *
- * @author Ines Montani
- * @version 0.0.1
- * @license MIT
- */
-
-/* Termynal terminal styling - aligned with Material for MkDocs theme */
-[data-termynal] {
- width: 750px;
- max-width: 100%;
- /* Use Material theme background colors that adapt to light/dark mode */
- background: var(--md-code-bg-color, #252a33);
- color: var(--md-code-fg-color, #eee);
- font-size: 15px;
- /* Use the same code font family as defined in the theme */
- font-family: var(--md-code-font);
- border-radius: 4px;
- padding: 50px 45px 30px;
- position: relative;
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
- line-height: 1.2;
- /* Add subtle border that adapts to theme */
- border: 1px solid var(--md-default-fg-color--lighter, rgba(0, 0, 0, 0.1));
-}
-
-/* Terminal window buttons (red, yellow, green) */
-[data-termynal]:before {
- content: '';
- position: absolute;
- top: 15px;
- left: 15px;
- display: inline-block;
- width: 12px;
- height: 12px;
- border-radius: 50%;
- background: #d9515d;
- -webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
- box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
-}
-
-/* Terminal label */
-[data-termynal]:after {
- content: 'bash';
- position: absolute;
- color: var(--color-text-subtle);
- top: 5px;
- left: 0;
- width: 100%;
- text-align: center;
-}
-
-/* Terminal control buttons (restart, fast forward) */
-a[data-terminal-control] {
- text-align: right;
- display: block;
- color: var(--color-text-subtle);
-}
-
-[data-ty] {
- display: block;
- line-height: 2;
-}
-
-[data-ty]:before {
- content: '';
- display: inline-block;
- vertical-align: middle;
-}
-
-[data-ty="input"]:before,
-[data-ty-prompt]:before {
- margin-right: 0.75em;
- color: var(--color-text-subtle);
-}
-
-[data-ty="input"]:before {
- content: '$';
-}
-
-[data-ty][data-ty-prompt]:before {
- content: attr(data-ty-prompt);
-}
-
-[data-ty-cursor]:after {
- content: attr(data-ty-cursor);
- font-family: var(--md-code-font), monospace;
- margin-left: 0.5em;
- -webkit-animation: blink 1s infinite;
- animation: blink 1s infinite;
-}
-
-@-webkit-keyframes blink {
- 50% {
- opacity: 0;
- }
-}
-
-@keyframes blink {
- 50% {
- opacity: 0;
- }
-}
diff --git a/docs/js/termynal.js b/docs/js/termynal.js
deleted file mode 100644
index 45bb371c..00000000
--- a/docs/js/termynal.js
+++ /dev/null
@@ -1,263 +0,0 @@
-/**
- * termynal.js
- * A lightweight, modern and extensible animated terminal window, using
- * async/await.
- *
- * @author Ines Montani
- * @version 0.0.1
- * @license MIT
- */
-
-'use strict';
-
-/** Generate a terminal widget. */
-class Termynal {
- /**
- * Construct the widget's settings.
- * @param {(string|Node)=} container - Query selector or container element.
- * @param {Object=} options - Custom settings.
- * @param {string} options.prefix - Prefix to use for data attributes.
- * @param {number} options.startDelay - Delay before animation, in ms.
- * @param {number} options.typeDelay - Delay between each typed character, in ms.
- * @param {number} options.lineDelay - Delay between each line, in ms.
- * @param {number} options.progressLength - Number of characters displayed as progress bar.
- * @param {string} options.progressChar – Character to use for progress bar, defaults to █.
- * @param {number} options.progressPercent - Max percent of progress.
- * @param {string} options.cursor – Character to use for cursor, defaults to ▋.
- * @param {Object[]} lineData - Dynamically loaded line data objects.
- * @param {boolean} options.noInit - Don't initialise the animation.
- */
- constructor(container = '#termynal', options = {}) {
- this.container = (typeof container === 'string') ? document.querySelector(container) : container;
- this.pfx = `data-${options.prefix || 'ty'}`;
- this.originalStartDelay = this.startDelay = options.startDelay
- || parseFloat(this.container.getAttribute(`${this.pfx}-startDelay`)) || 600;
- this.originalTypeDelay = this.typeDelay = options.typeDelay
- || parseFloat(this.container.getAttribute(`${this.pfx}-typeDelay`)) || 90;
- this.originalLineDelay = this.lineDelay = options.lineDelay
- || parseFloat(this.container.getAttribute(`${this.pfx}-lineDelay`)) || 1500;
- this.progressLength = options.progressLength
- || parseFloat(this.container.getAttribute(`${this.pfx}-progressLength`)) || 40;
- this.progressChar = options.progressChar
- || this.container.getAttribute(`${this.pfx}-progressChar`) || '█';
- this.progressPercent = options.progressPercent
- || parseFloat(this.container.getAttribute(`${this.pfx}-progressPercent`)) || 100;
- this.cursor = options.cursor
- || this.container.getAttribute(`${this.pfx}-cursor`) || '▋';
- this.lineData = this.lineDataToElements(options.lineData || []);
- this.loadLines()
- if (!options.noInit) this.init()
- }
-
- loadLines() {
- // Load all the lines and create the container so that the size is fixed
- // Otherwise it would be changing and the user viewport would be constantly
- // moving as she/he scrolls
- const finish = this.generateFinish()
- finish.style.visibility = 'hidden'
- this.container.appendChild(finish)
- // Appends dynamically loaded lines to existing line elements.
- this.lines = [...this.container.querySelectorAll(`[${this.pfx}]`)].concat(this.lineData);
- for (let line of this.lines) {
- line.style.visibility = 'hidden'
- this.container.appendChild(line)
- }
- const restart = this.generateRestart()
- restart.style.visibility = 'hidden'
- this.container.appendChild(restart)
- this.container.setAttribute('data-termynal', '');
- }
-
- /**
- * Initialise the widget, get lines, clear container and start animation.
- */
- init() {
- /**
- * Calculates width and height of Termynal container.
- * If container is empty and lines are dynamically loaded, defaults to browser `auto` or CSS.
- */
- const containerStyle = getComputedStyle(this.container);
- this.container.style.width = containerStyle.width !== '0px' ?
- containerStyle.width : undefined;
- this.container.style.minHeight = containerStyle.height !== '0px' ?
- containerStyle.height : undefined;
-
- this.container.setAttribute('data-termynal', '');
- this.container.innerHTML = '';
- for (let line of this.lines) {
- line.style.visibility = 'visible'
- }
- this.start();
- }
-
- /**
- * Start the animation and rener the lines depending on their data attributes.
- */
- async start() {
- this.addFinish()
- await this._wait(this.startDelay);
-
- for (let line of this.lines) {
- const type = line.getAttribute(this.pfx);
- const delay = line.getAttribute(`${this.pfx}-delay`) || this.lineDelay;
-
- if (type == 'input') {
- line.setAttribute(`${this.pfx}-cursor`, this.cursor);
- await this.type(line);
- await this._wait(delay);
- }
-
- else if (type == 'progress') {
- await this.progress(line);
- await this._wait(delay);
- }
-
- else {
- this.container.appendChild(line);
- await this._wait(delay);
- }
-
- line.removeAttribute(`${this.pfx}-cursor`);
- }
- this.addRestart()
- this.finishElement.style.visibility = 'hidden'
- this.lineDelay = this.originalLineDelay
- this.typeDelay = this.originalTypeDelay
- this.startDelay = this.originalStartDelay
- }
-
- generateRestart() {
- const restart = document.createElement('a')
- restart.onclick = (e) => {
- e.preventDefault()
- this.container.innerHTML = ''
- this.init()
- }
- restart.href = '#'
- restart.setAttribute('data-terminal-control', '')
- restart.innerHTML = "restart ↻"
- return restart
- }
-
- generateFinish() {
- const finish = document.createElement('a')
- finish.onclick = (e) => {
- e.preventDefault()
- this.lineDelay = 0
- this.typeDelay = 0
- this.startDelay = 0
- }
- finish.href = '#'
- finish.setAttribute('data-terminal-control', '')
- finish.innerHTML = "fast →"
- this.finishElement = finish
- return finish
- }
-
- addRestart() {
- const restart = this.generateRestart()
- this.container.appendChild(restart)
- }
-
- addFinish() {
- const finish = this.generateFinish()
- this.container.appendChild(finish)
- }
-
- /**
- * Animate a typed line.
- * @param {Node} line - The line element to render.
- */
- async type(line) {
- const chars = [...line.textContent];
- line.textContent = '';
- this.container.appendChild(line);
-
- for (let char of chars) {
- const delay = line.getAttribute(`${this.pfx}-typeDelay`) || this.typeDelay;
- await this._wait(delay);
- line.textContent += char;
- }
- }
-
- /**
- * Animate a progress bar.
- * @param {Node} line - The line element to render.
- */
- async progress(line) {
- const progressLength = line.getAttribute(`${this.pfx}-progressLength`)
- || this.progressLength;
- const progressChar = line.getAttribute(`${this.pfx}-progressChar`)
- || this.progressChar;
- const chars = progressChar.repeat(progressLength);
- const progressPercent = line.getAttribute(`${this.pfx}-progressPercent`)
- || this.progressPercent;
- line.textContent = '';
- this.container.appendChild(line);
-
- for (let i = 1; i < chars.length + 1; i++) {
- await this._wait(this.typeDelay);
- const percent = Math.round(i / chars.length * 100);
- line.textContent = `${chars.slice(0, i)} ${percent}%`;
- if (percent>progressPercent) {
- break;
- }
- }
- }
-
- /**
- * Helper function for animation delays, called with `await`.
- * @param {number} time - Timeout, in ms.
- */
- _wait(time) {
- return new Promise(resolve => setTimeout(resolve, time));
- }
-
- /**
- * Converts line data objects into line elements.
- *
- * @param {Object[]} lineData - Dynamically loaded lines.
- * @param {Object} line - Line data object.
- * @returns {Element[]} - Array of line elements.
- */
- lineDataToElements(lineData) {
- return lineData.map(line => {
- let div = document.createElement('div');
- div.innerHTML = `${line.value || ''}`;
-
- return div.firstElementChild;
- });
- }
-
- /**
- * Helper function for generating attributes string.
- *
- * @param {Object} line - Line data object.
- * @returns {string} - String of attributes.
- */
- _attributes(line) {
- let attrs = '';
- for (let prop in line) {
- // Custom add class
- if (prop === 'class') {
- attrs += ` class=${line[prop]} `
- continue
- }
- if (prop === 'type') {
- attrs += `${this.pfx}="${line[prop]}" `
- } else if (prop !== 'value') {
- attrs += `${this.pfx}-${prop}="${line[prop]}" `
- }
- }
- return attrs;
- }
-}
-
-/**
-* HTML API: If current script has container(s) specified, initialise Termynal.
-*/
-if (document.currentScript.hasAttribute('data-termynal-container')) {
- const containers = document.currentScript.getAttribute('data-termynal-container');
- containers.split('|')
- .forEach(container => new Termynal(container))
-}
diff --git a/uv.lock b/uv.lock
index 75684a26..7d0062c1 100644
--- a/uv.lock
+++ b/uv.lock
@@ -535,6 +535,7 @@ dependencies = [
{ name = "pystatx" },
{ name = "python-dateutil" },
{ name = "rich" },
+ { name = "termynal" },
{ name = "typing-extensions" },
]
diff --git a/zensical.toml b/zensical.toml
index eb588e48..b7912135 100644
--- a/zensical.toml
+++ b/zensical.toml
@@ -487,7 +487,7 @@ nav = [
#
# Read more: https://zensical.org/docs/customization/#additional-css
#
-extra_css = ["css/custom.css", "css/termynal.css"]
+extra_css = ["css/custom.css"]
# With the `extra_javascript` option you can add your own JavaScript to your
# project to customize the behavior according to your needs.
@@ -495,7 +495,7 @@ extra_css = ["css/custom.css", "css/termynal.css"]
# The path provided should be relative to the "docs_dir".
#
# Read more: https://zensical.org/docs/customization/#additional-javascript
-extra_javascript = ["js/termynal.js", "js/custom.js"]
+extra_javascript = ["js/custom.js"]
# ----------------------------------------------------------------------------
# Section for configuring theme options
@@ -777,7 +777,12 @@ extensions = [
{ griffe_pydantic = { schema = true } },
]
-[project.plugins.termynal]
+# [project.plugins.termynal]
+[project.markdown_extensions.termynal]
+include_assets = true
+title = "bash"
+buttons = "macos"
+prompt_literal_start = ["$"]
[project.markdown_extensions.attr_list]
[project.markdown_extensions.pymdownx.emoji]