From dacdc533da9d439e410bff5adf5d499e67789249 Mon Sep 17 00:00:00 2001 From: Stephan Hadan Date: Tue, 18 Feb 2025 12:28:37 +0100 Subject: [PATCH 1/2] added new software --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3ec80d0..fa41aba 100755 --- a/README.md +++ b/README.md @@ -307,8 +307,8 @@ Ein **Betriebssystem**, auch **OS** (von englisch *operating system*) genannt, i ### Continuous Integration / Continuous Delivery (CI/CD) -* [GitHub Actions](https://docs.github.com/de/actions) - Mit **GitHub Actions** kannst du deine Softwareentwicklungs-Workflows direkt in Ihrem Repository automatisieren, anpassen und ausführen. Actions wurden ebenso für Forgejo und Gitea implementiert und sind weitestgehendst kompatibel ![im Businesseinsatz][Business Icon] ![im Heimeinsatz][Home Icon] ![favorisiert][Favorite Icon] -* [GitLab CI]() - Gitlab's integrierte, voll funktionsfähige CI/CD-Lösung. ![im Businesseinsatz][Business Icon] +* [GitHub Actions](https://docs.github.com/de/actions) - Mit **GitHub Actions** kannst du deine Softwareentwicklungs-Workflows direkt in Ihrem Repository automatisieren, anpassen und ausführen. Actions wurden ebenso für [Forgejo](https://forgejo.org/docs/latest/user/actions/) und [Gitea](https://docs.gitea.com/usage/actions/overview) implementiert und sind weitestgehendst kompatibel ![im Businesseinsatz][Business Icon] ![im Heimeinsatz][Home Icon] ![favorisiert][Favorite Icon] +* [GitLab CI](https://docs.gitlab.com/ci/) - Gitlab's integrierte, voll funktionsfähige CI/CD-Lösung. ![im Businesseinsatz][Business Icon] * [GoCD](https://www.gocd.org/) - **GoCD** ist ein freier & quelloffener CI/CD-Server. Modellieren und visualisieren komplexe Arbeitsabläufe auf einfache Weise. ![im Businesseinsatz][Business Icon] ![favorisiert][Favorite Icon] * [Jenkins](https://www.jenkins.io/) - **Jenkins** ist ein erweiterbares, webbasiertes Software-System zur kontinuierlichen Integration von Software-Komponenten zu einem Anwendungsprogramm. ![im Businesseinsatz][Business Icon] ![favorisiert][Favorite Icon] * [Woodpecker CI](https://woodpecker-ci.org/) - **Woodpecker** ist eine einfache, aber leistungsstarke CI/CD-Engine mit großer Erweiterbarkeit. ![im Heimeinsatz][Home Icon] ![favorisiert][Favorite Icon] @@ -317,6 +317,7 @@ Ein **Betriebssystem**, auch **OS** (von englisch *operating system*) genannt, i * [Budibase](https://budibase.com/) - **Budibase** ist eine Open-Source-Workflow-Plattform, die Ingenieuren Zeit und Energie für die Entwicklung von Anwendungen spart, die mit jeder Datenquelle integriert werden können und jeden Prozess beschleunigen. ![im Businesseinsatz][Business Icon] * [NocoDB](https://nocodb.com/) - **NocoDB** ist der schnellste und einfachste Weg, Datenbanken online zu erstellen. ![im Heimeinsatz][Home Icon] ![favorisiert][Favorite Icon] +* [Rowy](https://www.rowy.io/) - Rowy ist eine Low-Code-Backend-Plattform. Verwalte Datenbanken über eine tabellenähnliche Benutzeroberfläche und erstelle Cloud-Funktionen in JS/TS, alles in Deinem Browser. ![versuchen][Bulb Icon] * [SeaTable](https://seatable.io/) - **SeaTable** ist eine No-Code-Plattform, bei der Anwender ohne Programmiererfahrung selbst Geschäftsprozesse entwickeln und umsetzen können. **SeaTable** vereint dabei traditionelle Fähigkeiten einer Tabellenkalkulation wie Excel und ergänzt diese um vielfältige Funktionen zur Prozessautomatisierung und -visualisierung sowie einer vollumfänglichen API. ![im Businesseinsatz][Business Icon] ![im Heimeinsatz][Home Icon] ![favorisiert][Favorite Icon] * [Microsoft Power Platform](https://microsoft.com/power-platform/) - **Microsoft Power Platform** ist eine Sammlung von Low-Code-Entwicklungstools, mit denen Benutzer benutzerdefinierte Geschäftsanwendungen erstellen, Arbeitsabläufe automatisieren und Daten analysieren können. Es bietet auch die Integration mit GitHub, Microsoft Azure, Microsoft Dynamics 365 und Microsoft Teams sowie anderen Microsoft- und Drittanbieteranwendungen. ![im Businesseinsatz][Business Icon] -- 2.45.3 From 3ab1c0c1190cf3ebfb7c79feacbff49c048d4157 Mon Sep 17 00:00:00 2001 From: Stephan Hadan Date: Tue, 18 Feb 2025 12:48:15 +0100 Subject: [PATCH 2/2] added styling --- idoc.yml | 1 + theme/default/css/copy.css | 49 + theme/default/css/demo-preview.css | 62 ++ theme/default/css/main.css | 338 +++++++ theme/default/css/media.css | 52 ++ theme/default/css/sidebar.css | 41 + theme/default/css/tocbot.css | 52 ++ theme/default/js/copy.js | 40 + theme/default/js/dark-mode.js | 162 ++++ theme/default/js/demo-preview.js | 31 + theme/default/js/giscus.js | 34 + theme/default/js/markdown-style.js | 1047 ++++++++++++++++++++++ theme/default/js/tocbot.js | 132 +++ theme/default/markdown.ejs | 18 + theme/default/partial/article-footer.ejs | 16 + theme/default/partial/chapters.ejs | 17 + theme/default/partial/footer.ejs | 10 + theme/default/partial/header.ejs | 34 + theme/default/partial/navigation.ejs | 29 + theme/default/partial/previous.ejs | 30 + theme/default/partial/tocs.ejs | 49 + 21 files changed, 2244 insertions(+) create mode 100644 theme/default/css/copy.css create mode 100644 theme/default/css/demo-preview.css create mode 100644 theme/default/css/main.css create mode 100644 theme/default/css/media.css create mode 100644 theme/default/css/sidebar.css create mode 100644 theme/default/css/tocbot.css create mode 100644 theme/default/js/copy.js create mode 100644 theme/default/js/dark-mode.js create mode 100644 theme/default/js/demo-preview.js create mode 100644 theme/default/js/giscus.js create mode 100644 theme/default/js/markdown-style.js create mode 100644 theme/default/js/tocbot.js create mode 100644 theme/default/markdown.ejs create mode 100644 theme/default/partial/article-footer.ejs create mode 100644 theme/default/partial/chapters.ejs create mode 100644 theme/default/partial/footer.ejs create mode 100644 theme/default/partial/header.ejs create mode 100644 theme/default/partial/navigation.ejs create mode 100644 theme/default/partial/previous.ejs create mode 100644 theme/default/partial/tocs.ejs diff --git a/idoc.yml b/idoc.yml index 17b2988..39ecfbe 100644 --- a/idoc.yml +++ b/idoc.yml @@ -17,6 +17,7 @@ menus: url: https://git.hadan-it.com/public/techstack.hadan.de/issues target: __blank +theme: theme/default #sideEffectFiles: # - editor-plugin.md diff --git a/theme/default/css/copy.css b/theme/default/css/copy.css new file mode 100644 index 0000000..c4b3093 --- /dev/null +++ b/theme/default/css/copy.css @@ -0,0 +1,49 @@ +markdown-style pre > .copied, +markdown-style [class*='language-'] .copied { + display: flex; + position: absolute; + cursor: pointer; + color: #a5afbb; + top: 6px; + right: 6px; + border-radius: 5px; + background: #82828226; + padding: 6px; + font-size: 12px; + transition: all 0.3s; + z-index: 10; +} +markdown-style pre > .copied:not(.active), +markdown-style [class*='language-'] .copied:not(.active) { + visibility: hidden; +} +markdown-style pre:hover > .copied, +markdown-style [class*='language-']:hover .copied { + visibility: visible; +} +markdown-style pre:hover > .copied:hover, +markdown-style [class*='language-']:hover .copied:hover { + background: #4caf50; + color: #fff; +} +markdown-style [class*='language-']:hover .copied:active, +markdown-style pre > .copied.active { + background: #2e9b33; + color: #fff; +} +markdown-style pre > .copied .octicon-copy, +markdown-style [class*='language-'] .copied .octicon-copy { + display: block; +} +markdown-style pre > .copied .octicon-check, +markdown-style [class*='language-'] .copied .octicon-check { + display: none; +} +markdown-style pre > .active .octicon-copy, +markdown-style [class*='language-'] .active .octicon-copy { + display: none; +} +markdown-style pre > .active .octicon-check, +markdown-style [class*='language-'] .active .octicon-check { + display: block; +} diff --git a/theme/default/css/demo-preview.css b/theme/default/css/demo-preview.css new file mode 100644 index 0000000..cc8a25e --- /dev/null +++ b/theme/default/css/demo-preview.css @@ -0,0 +1,62 @@ +.idoc-demo-warpper { + overflow: hidden; + min-height: 60px; + margin-bottom: 16px; +} + +div.idoc-demo-warpper { + position: relative; + background-color: var(--color-canvas-subtle); + border-radius: 6px; +} + +div.idoc-demo-warpper > pre { + padding: 16px; + overflow: auto; + display: block; + margin-bottom: 0 !important; + height: 100%; +} + +div.idoc-demo-previw { + padding: 10px; + font-size: initial; + line-height: initial; + line-height: initial; + font-family: initial; + overflow: auto; +} +.idoc-demo-previw { + border: 0; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + background-color: var(--color-canvas-subtle); + border: 1px solid var(--color-border-default); + border-radius: 6px; + z-index: 9; + transition: left 0.3s cubic-bezier(1, 0, 1, 0); +} + +.idoc-demo-previw.ishiden { + left: -100%; +} +button.idoc-toggle-previw { + user-select: none; + position: absolute; + z-index: 10; + border: transparent; + background-color: var(--color-border-default); + cursor: pointer; + font-size: 12px; + padding: 2px 5px; + border-radius: 3px; + bottom: 5px; + right: 5px; +} +button.idoc-toggle-previw:hover { + color: var(--color-theme-text); +} diff --git a/theme/default/css/main.css b/theme/default/css/main.css new file mode 100644 index 0000000..d613100 --- /dev/null +++ b/theme/default/css/main.css @@ -0,0 +1,338 @@ +[data-color-mode*='dark'], +[data-color-mode*='dark'] body { + --color-header-bg: #3a3a3a8f; + --color-header-border: #21262d7a; + --color-hover: #ffffff1c; + --color-hoc-bg: #fffefe08; + + --color-border-default: #d0d7de; + --color-accent-fg: #0969da; + --color-accent-emphasis: #0969da; + --color-danger-fg: #d1242f; + --color-danger-emphasis: #cf222e; + --color-attention-fg: #9a6700; + --color-attention-emphasis: #9a6700; + --color-done-fg: #8250df; + --color-done-emphasis: #8250df; + --color-success-fg: #1a7f37; + --color-success-emphasis: #1f883d; +} + +[data-color-mode*='light'], +[data-color-mode*='light'] body { + --color-header-bg: #ffffff52; + --color-header-border: #0000001c; + --color-hover: #0000001a; + --color-hoc-bg: #00000008; + + --color-border-default: #30363d; + --color-accent-fg: #58a6ff; + --color-accent-emphasis: #1f6feb; + --color-danger-fg: #f85149; + --color-danger-emphasis: #da3633; + --color-attention-fg: #d29922; + --color-attention-emphasis: #9e6a03; + --color-done-fg: #a371f7; + --color-done-emphasis: #8957e5; + --color-success-fg: #3fb950; + --color-success-emphasis: #238636; +} + +*, +:after, +:before { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + margin: 0; + font-size: 14px; + font-family: -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'; +} + +a { + text-decoration: none; + color: var(--color-accent-fg); +} +a:hover { + text-decoration: underline; +} + +.warpper { + max-width: 960px; + margin: 0 auto; +} + +.warpper dark-mode { + font-size: 18px; +} + +markdown-style { + min-height: 60vh; + grid-area: main; + margin-bottom: 18px !important; +} +markdown-style img { + background-color: transparent !important; +} + +.warpper-content { + padding: 0 20px; + padding-top: 32px; + margin-top: 48px; + display: grid; + grid-template-columns: minmax(0, 3.5fr) minmax(0, 15rem); + grid-template-areas: 'main toc'; + grid-gap: 18px; + gap: 18px; +} +.warpper-content.sidebar { + grid-template-columns: 180px minmax(0, 3.5fr) minmax(0, 15rem); + grid-template-areas: 'sidebar main toc'; +} +.warpper-content.notocs { + grid-template-columns: minmax(0, 3.5fr); + grid-template-areas: 'main'; +} +.warpper-content.sidebar.notocs { + grid-template-columns: 180px minmax(0, 3.5fr); + grid-template-areas: 'sidebar main'; +} + +nav.tocs .is-position-fixed { + top: 58px !important; + max-height: calc(100% - 68px); +} +nav.tocs { + position: relative; + grid-area: toc; +} +nav.tocs p { + color: var(--color-fg-muted); + margin-bottom: 0; +} +nav.tocs a { + color: var(--color-fg-muted); + display: block; + padding: 0 5px; +} +nav.tocs .inner { + padding: 10px 10px 10px 10px; + background-color: var(--color-hoc-bg); + max-width: 240px; + width: 240px; +} + +a.gototop { + position: fixed; + bottom: 10px; + right: 10px; + display: inline-block; + background: var(--color-theme-text); + padding: 5px; + border-radius: 5px; + z-index: 9999; + color: var(--color-theme-bg); + font-size: 10px; + opacity: 0; + transition: all 0.3s; +} +a.gototop:hover { + opacity: 1; +} + +.header { + position: fixed; + width: 100%; + background: var(--color-header-bg); + backdrop-filter: saturate(180%) blur(0.4rem); + background-color: var(--color-header-bg); + border-bottom: 1px solid var(--color-header-border); + z-index: 99; + top: 0; +} + +.header .inner { + display: flex; + justify-content: space-between; + min-height: 45px; + padding-left: 10px; + padding-right: 10px; +} +.header .logo { + font-weight: bold; + display: flex; + color: var(--color-theme-text); + align-items: center; +} +.header .logo:hover { + text-decoration: none; +} +.header .logo .title { + padding-left: 8px; + display: flex; +} +.header .logo .title sup { + margin-top: -5px; + padding-left: 2px; + font-weight: normal; + color: var(--color-fg-subtle); +} +.header .logo img, +.header .logo svg { + height: 26px; + display: block; +} + +.header .content { + display: flex; + align-items: center; +} + +.header .menu { + padding: 0; + margin: 0; + display: flex; + list-style: none; + padding-right: 10px; +} +.header .menu li { + display: flex; + align-items: center; +} +.header a { + color: var(--color-theme-text); + font-weight: bold; +} +.header .menu a { + padding: 3px 7px; + font-size: 14px; + border-radius: 2px; +} +.header .menu a.active { + background-color: var(--color-hover); +} + +.header .github { + width: 18px; + height: 18px; + margin-right: 8px; +} + +section.article-footer { + display: flex; + align-items: center; + font-size: 14px; + justify-content: space-between; + margin-top: 12px; +} + +section.article-footer a { + display: flex; + align-items: center; +} + +.edit-button { + padding-right: 8px; +} +.edit-button svg { + height: 15px; + margin-right: 6px; +} + +section.article-footer .atime { + font-size: 12px; + color: var(--color-fg-muted); + margin-top: 2px; +} + +.previous { + display: flex; + align-items: center; + justify-content: space-between; + grid-gap: 12px; + gap: 12px; + background-color: var(--color-canvas-subtle); + padding: 10px; + font-size: 14px; + border-radius: 5px; + margin-top: 26px; +} +.previous a { + display: flex; + align-items: center; +} +.previous a.prev svg { + margin-right: 3px; +} +.previous a.next svg { + margin-left: 3px; +} + +.footer { + text-align: center; + border-top: 1px solid var(--color-header-border); + padding: 32px 0 110px 0; + color: var(--color-fg-muted); + font-size: 14px; +} + +.markdown-alert { + border-left: 0.25em solid var(--borderColor-default, var(--color-border-default)); + color: inherit; + margin-bottom: 16px; + padding: 0.5rem 1em; +} +.markdown-alert > :last-child { + margin-bottom: 0 !important; +} +.markdown-alert .markdown-alert-title { + align-items: center; + display: flex; + font-size: 14px; + font-weight: 500; + line-height: 1; +} +.markdown-alert .markdown-alert-title svg.octicon { + margin-right: 8px !important; + margin-right: var(--base-size-8, 8px) !important; +} +.markdown-alert.markdown-alert-note { + border-left-color: var(--borderColor-accent-emphasis, var(--color-accent-emphasis)); +} +.markdown-alert.markdown-alert-note .markdown-alert-title { + color: var(--color-accent-fg); + color: var(--fgColor-accent, var(--color-accent-fg)); +} +.markdown-alert.markdown-alert-tip { + border-left-color: var(--borderColor-success-emphasis, var(--color-success-emphasis)); +} +.markdown-alert.markdown-alert-tip .markdown-alert-title { + color: var(--color-success-fg); + color: var(--fgColor-success, var(--color-success-fg)); +} +.markdown-alert.markdown-alert-important { + border-left-color: var(--borderColor-done-emphasis, var(--color-done-emphasis)); +} +.markdown-alert.markdown-alert-important .markdown-alert-title { + color: var(--color-done-fg); + color: var(--fgColor-done, var(--color-done-fg)); +} +.markdown-alert.markdown-alert-warning { + border-left-color: var(--borderColor-attention-emphasis, var(--color-attention-emphasis)); +} +.markdown-alert.markdown-alert-warning .markdown-alert-title { + color: var(--color-attention-fg); + color: var(--fgColor-attention, var(--color-attention-fg)); +} +.markdown-alert.markdown-alert-caution { + border-left-color: var(--borderColor-danger-emphasis, var(--color-danger-emphasis)); +} +.markdown-alert.markdown-alert-caution .markdown-alert-title { + color: var(--color-danger-fg); + color: var(--fgColor-danger, var(--color-danger-fg)); +} diff --git a/theme/default/css/media.css b/theme/default/css/media.css new file mode 100644 index 0000000..da52435 --- /dev/null +++ b/theme/default/css/media.css @@ -0,0 +1,52 @@ +@media only screen and (min-width: 1024px) { + footer.article-footer, + .warpper { + max-width: 1200px; + } +} + +@media screen and (max-width: 900px) { + .warpper-content { + grid-template-columns: minmax(0, 3.5fr); + grid-template-areas: 'main'; + } + .warpper-content.sidebar { + grid-template-areas: 'sidebar main'; + grid-template-columns: 180px minmax(0, 41rem); + } + nav.tocs { + display: none; + } +} + +@media screen and (max-width: 600px) { + .warpper-content { + grid-template-columns: minmax(0, 3.5fr); + grid-template-areas: 'main'; + } + .warpper-content.sidebar { + grid-template-areas: 'main'; + grid-template-columns: minmax(0, 41rem); + } + nav.tocs, + .sidebar-border { + display: none; + } +} + +@media print { + .header, + nav.tocs, + section.article-footer, + .sidebar-border, + .previous, + .footer, + a.gototop { + display: none; + } + .warpper-content { + margin: 0; + padding: 0; + display: initial; + } +} diff --git a/theme/default/css/sidebar.css b/theme/default/css/sidebar.css new file mode 100644 index 0000000..11a6999 --- /dev/null +++ b/theme/default/css/sidebar.css @@ -0,0 +1,41 @@ +.sidebar-border { + border-right: 1px solid var(--color-border-muted); +} +aside.sidebar { + min-width: 160px; + margin-left: -5px; + padding-bottom: 20px; + padding-right: 6px; + position: -webkit-sticky; + position: sticky; + top: 56px; + grid-area: sidebar; + overflow: auto; + max-height: calc(100vh - 56px); + padding-bottom: 36px; +} +aside.sidebar label:first-child { + padding-top: 0 !important; +} +aside.sidebar a:first-child { + margin-top: 0 !important; +} +aside.sidebar label { + font-size: 12px; + padding: 5px 0 3px 0; + display: block; + padding-left: 5px !important; +} +aside.sidebar a.active { + color: var(--color-prettylights-syntax-markup-inserted-text); + background-color: var(--color-hover); +} +aside.sidebar a { + display: block; + padding: 3px 5px 3px 5px; + border-radius: 3px; + margin: 3px 0; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} diff --git a/theme/default/css/tocbot.css b/theme/default/css/tocbot.css new file mode 100644 index 0000000..3c374ce --- /dev/null +++ b/theme/default/css/tocbot.css @@ -0,0 +1,52 @@ +.tocs { + line-height: 26px; +} +nav.tocs > .inner { + position: sticky; + top: 56px; + overflow: auto; + max-height: calc(100vh - 56px); +} +nav.tocs .inner > .tocs-list { + overflow: hidden; + position: relative; +} +.tocs .tocs-list li { + list-style: none; +} +.tocs-list { + margin: 0; + padding-left: 10px; +} +.tocs-list.is-collapsed { + max-height: 0; + overflow: hidden; + transition: max-height 0.3s cubic-bezier(0, 1, 0, 1); +} +.tocs-list.is-collapsed.is-open { + max-height: 9999px; + transition: max-height 0.3s cubic-bezier(1, 0, 1, 0); +} + +.tocs-link { + height: 100%; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} +.tocs-link::before { + background-color: var(--color-border-default); + content: ' '; + display: inline-block; + height: inherit; + left: 0; + margin-top: -1px; + position: absolute; + width: 2px; +} +.tocs-link.is-active-link { + font-weight: 700; +} +.tocs-link.is-active-link::before { + background-color: #54bc4b; +} diff --git a/theme/default/js/copy.js b/theme/default/js/copy.js new file mode 100644 index 0000000..ec77c45 --- /dev/null +++ b/theme/default/js/copy.js @@ -0,0 +1,40 @@ +/** + * https://github.com/uiwjs/copy-to-clipboard/blob/master/src/main.js + */ +function copyTextToClipboard(text, cb) { + const el = document.createElement('textarea'); + el.value = text; + el.setAttribute('readonly', ''); + el.style = { + position: 'absolute', + left: '-9999px', + }; + document.body.appendChild(el); + const selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false; + el.select(); + let isCopy = false; + try { + const successful = document.execCommand('copy'); + isCopy = !!successful; + } catch (err) { + isCopy = false; + } + document.body.removeChild(el); + if (selected && document.getSelection) { + document.getSelection().removeAllRanges(); + document.getSelection().addRange(selected); + } + cb && cb(isCopy); +} + +function copied(target, str) { + target.classList.add('active'); + const input = target.parentElement.querySelector('input'); + if (input) { + copyTextToClipboard(input.value || '', function () { + setTimeout(() => { + target.classList.remove('active'); + }, 2000); + }); + } +} diff --git a/theme/default/js/dark-mode.js b/theme/default/js/dark-mode.js new file mode 100644 index 0000000..50a0165 --- /dev/null +++ b/theme/default/js/dark-mode.js @@ -0,0 +1,162 @@ +/** + * @package @wcj/dark-mode@1.0.14 + * Web Component that toggles dark mode 🌒 + * Github: https://github.com/jaywcjlove/dark-mode.git + * Website: https://jaywcjlove.github.io/dark-mode + * + * Licensed under the MIT license. + * @license Copyright © 2022. Licensed under the MIT License + * @author kenny wong + */ +const t = document; +const e = '_dark_mode_theme_'; +const s = 'permanent'; +const o = 'colorschemechange'; +const i = 'permanentcolorscheme'; +const h = 'light'; +const r = 'dark'; +const n = (t, e, s = e) => { + Object.defineProperty(t, s, { + enumerable: true, + get() { + const t = this.getAttribute(e); + return t === null ? '' : t; + }, + set(t) { + this.setAttribute(e, t); + }, + }); +}; +const c = (t, e, s = e) => { + Object.defineProperty(t, s, { + enumerable: true, + get() { + return this.hasAttribute(e); + }, + set(t) { + if (t) { + this.setAttribute(e, ''); + } else { + this.removeAttribute(e); + } + }, + }); +}; +class a extends HTMLElement { + static get observedAttributes() { + return ['mode', h, r, s]; + } + LOCAL_NANE = e; + constructor() { + super(); + this.t(); + } + connectedCallback() { + n(this, 'mode'); + n(this, r); + n(this, h); + c(this, s); + const a = localStorage.getItem(e); + if (a && [h, r].includes(a)) { + this.mode = a; + this.permanent = true; + } + if (this.permanent && !a) { + localStorage.setItem(e, this.mode); + } + const l = [h, r].includes(a); + if (this.permanent && a) { + this.o(); + } else { + if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { + this.mode = r; + this.o(); + } + if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) { + this.mode = h; + this.o(); + } + } + if (!this.permanent && !l) { + window.matchMedia('(prefers-color-scheme: light)').onchange = (t) => { + this.mode = t.matches ? h : r; + this.o(); + }; + window.matchMedia('(prefers-color-scheme: dark)').onchange = (t) => { + this.mode = t.matches ? r : h; + this.o(); + }; + } + const d = new MutationObserver((s, h) => { + this.mode = t.documentElement.dataset.colorMode; + if (this.permanent && l) { + localStorage.setItem(e, this.mode); + this.i(i, { permanent: this.permanent }); + } + this.h(); + this.i(o, { colorScheme: this.mode }); + }); + d.observe(t.documentElement, { attributes: true }); + this.i(o, { colorScheme: this.mode }); + this.h(); + } + attributeChangedCallback(t, s, o) { + if (t === 'mode' && s !== o && [h, r].includes(o)) { + const t = localStorage.getItem(e); + if (this.mode === t) { + this.mode = o; + this.h(); + this.o(); + } else if (this.mode && this.mode !== t) { + this.h(); + this.o(); + } + } else if ((t === h || t === r) && s !== o) { + this.h(); + } + if (t === 'permanent' && typeof this.permanent === 'boolean') { + this.permanent ? localStorage.setItem(e, this.mode) : localStorage.removeItem(e); + } + } + o() { + t.documentElement.setAttribute('data-color-mode', this.mode); + } + h() { + this.icon.textContent = this.mode === h ? '🌒' : '🌞'; + this.text.textContent = this.mode === h ? this.getAttribute(r) : this.getAttribute(h); + } + t() { + var s = this.attachShadow({ mode: 'open' }); + this.label = t.createElement('span'); + this.label.setAttribute('class', 'wrapper'); + this.label.onclick = () => { + this.mode = this.mode === h ? r : h; + if (this.permanent) { + localStorage.setItem(e, this.mode); + } + this.o(); + this.h(); + }; + s.appendChild(this.label); + this.icon = t.createElement('span'); + this.label.appendChild(this.icon); + this.text = t.createElement('span'); + this.label.appendChild(this.text); + const o = `\n[data-color-mode*='dark'], [data-color-mode*='dark'] body {\n color-scheme: dark;\n --color-theme-bg: #0d1117;\n --color-theme-text: #c9d1d9;\n background-color: var(--color-theme-bg);\n color: var(--color-theme-text);\n}\n\n[data-color-mode*='light'], [data-color-mode*='light'] body {\n color-scheme: light;\n --color-theme-bg: #fff;\n --color-theme-text: #24292f;\n background-color: var(--color-theme-bg);\n color: var(--color-theme-text);\n}`; + const i = '_dark_mode_style_'; + const n = t.getElementById(i); + if (!n) { + var c = t.createElement('style'); + c.id = i; + c.textContent = o; + t.head.appendChild(c); + } + var a = t.createElement('style'); + a.textContent = `\n .wrapper { cursor: pointer; user-select: none; position: relative; }\n .wrapper > span + span { margin-left: .4rem; }\n `; + s.appendChild(a); + } + i(t, e) { + this.dispatchEvent(new CustomEvent(t, { bubbles: true, composed: true, detail: e })); + } +} +customElements.define('dark-mode', a); diff --git a/theme/default/js/demo-preview.js b/theme/default/js/demo-preview.js new file mode 100644 index 0000000..05d088a --- /dev/null +++ b/theme/default/js/demo-preview.js @@ -0,0 +1,31 @@ +const demo = document.querySelectorAll('.idoc-demo-warpper .idoc-demo-previw'); + +function getButton(elm, type = 'BUTTON') { + let btn; + do { + elm = elm.nextElementSibling; + if (elm.tagName === type) { + btn = elm; + elm = undefined; + break; + } + } while (elm); + return btn; +} +if (demo && demo.length > 0) { + demo.forEach((item) => { + if (item.previousElementSibling && item.previousElementSibling.tagName === 'INPUT') { + const button = getButton(item); + if (button) { + button.innerHTML = item.classList.contains('ishiden') ? 'Preview' : 'Show Code'; + if (item.tagName === 'DIV') { + item.innerHTML = item.previousElementSibling.defaultValue; + } + button.onclick = () => { + item.classList.toggle('ishiden'); + button.innerHTML = item.classList.contains('ishiden') ? 'Preview' : 'Show Code'; + }; + } + } + }); +} diff --git a/theme/default/js/giscus.js b/theme/default/js/giscus.js new file mode 100644 index 0000000..1e0fd5b --- /dev/null +++ b/theme/default/js/giscus.js @@ -0,0 +1,34 @@ +(() => { + const targetElement = document.documentElement; + const defaultTheme = targetElement.getAttribute('data-color-mode'); + changeGiscusTheme(defaultTheme); + const observer = new MutationObserver((mutationsList, observer) => { + for (const mutation of mutationsList) { + if (mutation.type === 'attributes') { + const value = targetElement.getAttribute('data-color-mode'); + changeGiscusTheme(value); + } + } + }); + + observer.observe(targetElement, { + attributes: true, + attributeOldValue: true, + }); + + function changeGiscusTheme(theme = 'light') { + const iframe = document.querySelector('.giscus-frame'); + if (iframe) { + const config = { + giscus: { + setConfig: { + theme: theme.toLocaleLowerCase(), + }, + }, + }; + iframe.contentWindow.postMessage(config, 'https://giscus.app'); + const script = document.querySelector('script[data-script-id="giscus"]'); + script.setAttribute('data-theme', theme); + } + } +})(); diff --git a/theme/default/js/markdown-style.js b/theme/default/js/markdown-style.js new file mode 100644 index 0000000..b4aa91e --- /dev/null +++ b/theme/default/js/markdown-style.js @@ -0,0 +1,1047 @@ +/** + * Markdown Style + * @version 1.1.0 + * @author 小弟调调 + * https://github.com/jaywcjlove/markdown-style + * + * Integrate markdown styles into web components, Markdown CSS styles will not be conflicted. + * The minimal amount of CSS to replicate the GitHub Markdown style. Support dark-mode/night mode. + */ +const octiconLinkStyle = ` +markdown-style h1:hover a.anchor .icon-link:before, +markdown-style h2:hover a.anchor .icon-link:before, +markdown-style h3:hover a.anchor .icon-link:before, +markdown-style h4:hover a.anchor .icon-link:before, +markdown-style h5:hover a.anchor .icon-link:before, +markdown-style h6:hover a.anchor .icon-link:before { + width: 16px; + height: 16px; + content: ' '; + display: inline-block; + background-color: currentColor; + -webkit-mask-image: url("data:image/svg+xml,"); + mask-image: url("data:image/svg+xml,"); +}`; + +const __TEMPLATE__ = document.createElement('template'); +__TEMPLATE__.innerHTML = ` + + +`; +class MarkdownStyle extends HTMLElement { + get theme() { + const value = this.getAttribute('theme'); + return value === null ? '' : value; + } + set theme(name) { + this.setAttribute('theme', name); + } + constructor() { + super(); + this.shadow = this.attachShadow({ mode: 'open' }); + this.shadow.appendChild(__TEMPLATE__.content.cloneNode(true)); + const style = Array.prototype.slice.call(this.shadow.children).find((item) => item.tagName === 'STYLE'); + if (style) { + const id = '__MARKDOWN_STYLE__'; + const findStyle = document.getElementById(id); + if (!findStyle) { + style.id = id; + document.head.append(style); + } + } + } + connectedCallback() { + const disableThemeAutoSwitch = this.getAttribute('theme-auto-switch-disabled'); + if (disableThemeAutoSwitch == '' || (disableThemeAutoSwitch && disableThemeAutoSwitch.toLowerCase() === 'true')) { + return; + } + if (!this.theme) { + const { colorMode } = document.documentElement.dataset; + this.theme = colorMode; + const observer = new MutationObserver((mutationsList, observer) => { + this.theme = document.documentElement.dataset.colorMode; + }); + observer.observe(document.documentElement, { attributes: true }); + window.matchMedia('(prefers-color-scheme: light)').onchange = (event) => { + this.theme = event.matches ? 'light' : 'dark'; + }; + window.matchMedia('(prefers-color-scheme: dark)').onchange = (event) => { + this.theme = event.matches ? 'dark' : 'light'; + }; + } + } +} +customElements.define('markdown-style', MarkdownStyle); diff --git a/theme/default/js/tocbot.js b/theme/default/js/tocbot.js new file mode 100644 index 0000000..a7e89de --- /dev/null +++ b/theme/default/js/tocbot.js @@ -0,0 +1,132 @@ +(() => { + function debounce(fn, delay = 1000) { + let time = null; + function _debounce(...args) { + if (time !== null) clearTimeout(time); + time = setTimeout(() => fn.apply(this, args), delay); + } + return _debounce; + } + + const scrollSmoothOffset = 56; + function updateScroll() { + const heading = document.getElementById(decodeURIComponent(location.hash.replace(/^#/, ''))); + if (heading) { + document.scrollingElement.scrollTop = heading.offsetTop - scrollSmoothOffset + 3; + } + } + + function preventClickHandle(selector) { + const mdContainer = document.querySelectorAll(selector); + if (mdContainer && mdContainer.length > 0) { + mdContainer.forEach((anchor) => { + anchor.addEventListener('click', (e) => { + e.preventDefault(); + location.hash = anchor.getAttribute('href'); + updateScroll(); + updateAnchor(); + tocsCollapse(); + }); + }); + } + } + function tocButton() { + const tocElement = document.querySelector(`a.gototop`); + if (document.body.scrollTop > 50 || document.documentElement.scrollTop > 50) { + tocElement.style.opacity = 0.5; + } else { + tocElement.style.opacity = 0; + } + } + function scrollListener(evn) { + const anchors = document.querySelectorAll('markdown-style a.anchor[href*="#"][aria-hidden]'); + const scrollTop = evn && evn.target && evn.target.scrollingElement && evn.target.scrollingElement.scrollTop; + let element; + let index = 0; + anchors.forEach((anchor, idx) => { + if (anchor.offsetTop - scrollSmoothOffset < scrollTop || (idx === 0 && anchor.offsetTop > scrollTop)) { + element = anchor; + index = idx; + } + }); + tocButton(); + if (element) { + const tocElement = document.querySelector(`a.tocs-link[href='${decodeURIComponent(element.hash)}']`); + if (tocElement) { + updateAnchor(tocElement); + tocsCollapse(tocElement); + } else { + const first = document.querySelector('a.tocs-link[href*="#"]'); + if (index === 0 && first) { + updateAnchor(first); + tocsCollapse(first); + } + } + } + } + + document.addEventListener('scroll', debounce(scrollListener, 30), false); + + function updateAnchor(element) { + const anchorContainer = document.querySelectorAll('.tocs aside.inner.toc a.tocs-link'); + anchorContainer.forEach((tocanchor) => { + tocanchor.classList.remove('is-active-link'); + }); + const anchor = element || document.querySelector(`a.tocs-link[href='${decodeURIComponent(location.hash)}']`); + if (anchor) { + anchor.classList.add('is-active-link'); + } + } + + function tocsCollapse(element) { + const tocContainer = document.querySelector('nav.tocs > aside.inner.toc'); + if (element) { + tocContainer.scrollTop = element.offsetTop; + } + + const list = document.querySelectorAll('aside.toc ol.tocs-list'); + list.forEach((item) => { + item.classList.remove('is-open'); + }); + if (element && element.nextElementSibling) { + element.nextElementSibling.classList.add('is-open'); + } + isOpen(element); + } + + function isOpen(element) { + if (!element) { + element = document.querySelector(`a.tocs-link[href='${decodeURIComponent(location.hash)}']`); + } + if ( + element && + element.parentElement && + element.parentElement.tagName !== 'ASIDE' && + !element.parentElement.classList.contains('toc') + ) { + isOpen(element.parentElement); + if (element.parentElement.classList.contains('is-collapsed')) { + element.parentElement.classList.add('is-open'); + } + } + } + + preventClickHandle('markdown-style a.anchor[href*="#"][aria-hidden]'); + preventClickHandle('.tocs aside.inner.toc a.tocs-link'); + + function updateSiderBarScroll() { + const siderBar = document.querySelector(".sidebar[role*='navigation']"); + const siderAnchor = document.querySelector(".sidebar[role*='navigation'] a[class*='active']"); + if (siderAnchor) { + siderBar.scrollTop = siderAnchor.offsetTop; + } + } + + const timer = setTimeout(() => { + updateSiderBarScroll(); + updateScroll(); + updateAnchor(); + tocsCollapse(); + clearTimeout(timer); + }, 100); +})(); diff --git a/theme/default/markdown.ejs b/theme/default/markdown.ejs new file mode 100644 index 0000000..f8f16f8 --- /dev/null +++ b/theme/default/markdown.ejs @@ -0,0 +1,18 @@ +<%- include('partial/header'); %> +<%- include('partial/navigation'); %> + +
class="warpper-content warpper <%= chapters && chapters.length > 0 ? 'sidebar' : ''%> <%= tocsTree && tocsTree.length > 0 ? '' : 'notocs'%>"> + <%- include('partial/chapters'); %> + + <%- html %> + <%- giscusScript %> + <% if (giscusScript) { %> + + <% } %> + <%- include('partial/article-footer'); %> + + <%- include('partial/tocs'); %> +
+ + +<%- include('partial/footer'); %> \ No newline at end of file diff --git a/theme/default/partial/article-footer.ejs b/theme/default/partial/article-footer.ejs new file mode 100644 index 0000000..2debcf1 --- /dev/null +++ b/theme/default/partial/article-footer.ejs @@ -0,0 +1,16 @@ + +<%- include('previous'); %> + +<% if (editButton && editButton.url && editButton.label) { %> + +<% } %> \ No newline at end of file diff --git a/theme/default/partial/chapters.ejs b/theme/default/partial/chapters.ejs new file mode 100644 index 0000000..62ada11 --- /dev/null +++ b/theme/default/partial/chapters.ejs @@ -0,0 +1,17 @@ +<% if (chapters && chapters.length > 0) {%> + +<% } %> \ No newline at end of file diff --git a/theme/default/partial/footer.ejs b/theme/default/partial/footer.ejs new file mode 100644 index 0000000..b273479 --- /dev/null +++ b/theme/default/partial/footer.ejs @@ -0,0 +1,10 @@ +<% if (footer) { %> + +<% } %> + + + + + \ No newline at end of file diff --git a/theme/default/partial/header.ejs b/theme/default/partial/header.ejs new file mode 100644 index 0000000..594f4ac --- /dev/null +++ b/theme/default/partial/header.ejs @@ -0,0 +1,34 @@ + + + + + + + <%= title %> <%= site.replace(/<\/?sup>/g, '') %> + <% if (description) { %> + + <% }%> + <% if (keywords) { %> + + <% }%> + <% (meta || []).forEach((val) => { %> + <%- val %> + <% }) %> + + + + + + + <% if (favicon.href) { %> + + <% } else if (favicon.base64) { %> + + <% } %> + + + + + + + top \ No newline at end of file diff --git a/theme/default/partial/navigation.ejs b/theme/default/partial/navigation.ejs new file mode 100644 index 0000000..493affb --- /dev/null +++ b/theme/default/partial/navigation.ejs @@ -0,0 +1,29 @@ +
+ +
\ No newline at end of file diff --git a/theme/default/partial/previous.ejs b/theme/default/partial/previous.ejs new file mode 100644 index 0000000..7c9f26e --- /dev/null +++ b/theme/default/partial/previous.ejs @@ -0,0 +1,30 @@ +<% if ((page.prevPage && page.prevPage.href && page.prevPage.label) || (page.nextPage && page.nextPage.href && page.nextPage.label)) { %> + +<% } %> \ No newline at end of file diff --git a/theme/default/partial/tocs.ejs b/theme/default/partial/tocs.ejs new file mode 100644 index 0000000..b350cd2 --- /dev/null +++ b/theme/default/partial/tocs.ejs @@ -0,0 +1,49 @@ +<% if (tocsTree && tocsTree.length > 0) { %> + +<% } %> \ No newline at end of file -- 2.45.3