Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
9dfde0a
feature: provide progress state of page to sidebar
lebalz Oct 15, 2025
a1a499a
make linter happy
lebalz Oct 15, 2025
5536736
Merge branch 'main' into feature/page-progress-state
lebalz Oct 15, 2025
f785608
Merge branch 'main' into feature/page-progress-state
lebalz Oct 19, 2025
3464f52
basic exporter
lebalz Oct 19, 2025
2cd2a9f
account border width in html sandbox
lebalz Oct 20, 2025
b114f15
fix missing null check
lebalz Oct 20, 2025
718b7a2
Merge branch 'main' into feature/page-progress-state
lebalz Oct 31, 2025
7f89faf
add experiments
lebalz Nov 3, 2025
62ed118
Merge branch 'main' into feature/page-progress-state
lebalz Dec 19, 2025
4634aab
fix docusaurus config
lebalz Dec 19, 2025
52378a1
Merge branch 'main' into feature/page-progress-state
lebalz Jan 26, 2026
1e37506
poc of gathering doc ids
lebalz Jan 26, 2026
fae0d57
better config option
lebalz Jan 27, 2026
4bed87a
Merge branch 'feature/gather-doc-ids' into feature/page-progress-state
lebalz Jan 27, 2026
df06f79
work to synchronize pocs
lebalz Jan 27, 2026
e66da9e
poc
lebalz Jan 27, 2026
c5d82bd
load pageStore on load
lebalz Jan 27, 2026
2ed6473
refactor page-progress-state
lebalz Jan 27, 2026
03b52e4
generate Page models from loaded index
lebalz Jan 28, 2026
e6f8646
create page tree
lebalz Jan 28, 2026
ba0d1cb
update loading behavior
lebalz Jan 28, 2026
6a99db5
add init load
lebalz Jan 28, 2026
ca063f7
poc
lebalz Jan 28, 2026
4c6db53
add taskableDocs
lebalz Jan 29, 2026
21bc5f0
load docs on the fly
lebalz Jan 29, 2026
e9bf794
debug print metas
lebalz Jan 29, 2026
66a15c9
update page position calculation
lebalz Jan 29, 2026
124d503
add taskable doc
lebalz Jan 31, 2026
1c5622f
use taskable
lebalz Jan 31, 2026
0dacd41
split gh deploy steps
lebalz Feb 2, 2026
480f784
use latest dependencies
lebalz Feb 2, 2026
cba7b77
ensure deterministic order
lebalz Feb 2, 2026
3d5903e
add dev reload
lebalz Feb 2, 2026
c247a64
add totalSteps to progress_state docs
lebalz Feb 2, 2026
8e2598f
rm unused state
lebalz Feb 3, 2026
7953541
rm meta display
lebalz Feb 3, 2026
644e033
support taskable actions through frontmatter
lebalz Feb 4, 2026
37c7887
add docs
lebalz Feb 4, 2026
85a6c32
derive tdev root path
lebalz Feb 4, 2026
0368e23
refactor: rename to @tdev/page-index
lebalz Feb 4, 2026
717bd9e
update page tree
lebalz Feb 4, 2026
bbfd7d7
export default options
lebalz Feb 4, 2026
483f8ba
support strings as doctype too
lebalz Feb 4, 2026
f576751
move TaskableState to the plugin
lebalz Feb 4, 2026
4ec63cf
add todo
lebalz Feb 4, 2026
fdf7f05
fix image sync in packages
lebalz Feb 4, 2026
4256117
document implementation for plugin authors
lebalz Feb 4, 2026
f2ab1cf
update md plugin config
lebalz Feb 5, 2026
0c941bb
rm gitignore
lebalz Feb 5, 2026
7e74c66
move dependencies to page-index plugin
lebalz Feb 5, 2026
41a9700
undo useless change
lebalz Feb 5, 2026
000ca97
display generated page index
lebalz Feb 5, 2026
c8551de
remove unused page tree
lebalz Feb 5, 2026
41da3dc
cleanup ux experience
lebalz Feb 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ jobs:
with:
node-version: '>=24.13.0'
cache: yarn
- name: Install dependencies and build website
- name: Install dependencies
run: yarn install
- name: Build Site
env:
APP_URL: ${{ secrets.APP_URL }}
BACKEND_URL: ${{ secrets.BACKEND_URL }}
GH_OAUTH_CLIENT_ID: ${{ vars.GH_OAUTH_CLIENT_ID}}
SITE_CONFIG_PATH: ${{ vars.SITE_CONFIG_PATH }}
run: |
yarn install
yarn build
run: yarn build
working-directory: .
- name: Upload Build Artifact
uses: actions/upload-pages-artifact@v3
Expand Down
6 changes: 4 additions & 2 deletions docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
socketIoNoDepWarningsPluginConfig,
aliasConfigurationPlugin
} from './src/siteConfig/pluginConfigs';
import pageIndexPlugin from './packages/tdev/page-index/plugin';
import { useTdevContentPath } from './src/siteConfig/helpers';
import path from 'path';
import {
Expand Down Expand Up @@ -383,7 +384,8 @@ const docusaurusConfig = withSiteConfig().then(async (siteConfig) => {
...(siteConfig.pages || {})
}
],
...((siteConfig.plugins as Config['plugins']) || [])
...((siteConfig.plugins as Config['plugins']) || []),
pageIndexPlugin
],
themes: [
'@docusaurus/theme-mermaid',
Expand All @@ -405,4 +407,4 @@ const docusaurusConfig = withSiteConfig().then(async (siteConfig) => {
return config;
});

export default docusaurusConfig;
export default docusaurusConfig;
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,6 @@
"vfile": "^6.0.3",
"vitest": "^2.0.5"
},
"resolutions": {
"@rspack/core": "1.6.5"
},
"peerDependencies": {
"react-hook-form": "*"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/tdev/brython-code/README.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
page_id: e7bde0ab-c0fe-4225-8325-e4ebc22d414b
page_id: 0f9fe018-9c46-4ec0-be50-c2ae69a6a005
tags:
- '@tdev/'
- python
Expand Down
204 changes: 204 additions & 0 deletions packages/tdev/page-index/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
---
page_id: cfbd9607-c2d5-4c2a-82e0-9f39c5756747
tags:
- '@tdev/'
---

import { useStore } from '@tdev-hooks/useStore'
import { observer } from 'mobx-react-lite';
import CodeBlock from '@theme/CodeBlock';
import JsObjectViewer from '@tdev-components/shared/JsObject/Viewer';

# page-index

Dieses Plugin ermöglicht eine Übersicht über alle speicherbaren Dokumente. So kann bspw. der Bearbeitungsstand in der Seitenleiste angezeigt werden.

Standardmässig wird in der Seitenleiste der Bearbeitungsstand in zwei Fällen angezeigt:
1. Auf einer Seite sind *Statusdokument* vorhanden, deren Fortschritt bestimmt werden kann (sog. `TaskableDocuments`, bspw. `task_state` oder `progress_state`).
2. In einer Kategorie befinden sich direkt untergeordnete Seiten mit *Statusdokumenten*.

![--width=800px](./images/taskable-sidebar.png)

Dieses Verhalten kann über das *Frontmatter* der Seite angepasst werden:

:::cards{flexBasis="300px"}
```yaml
---
sidebar_custom_props:
taskable_state: 'show'
---
```
Bearbeitungsstand anzeigen, auch wenn keine Statusdokumente in den direkt untergeordneten Seiten vorhanden sind.
::br
```yaml
---
sidebar_custom_props:
taskable_state: 'hide'
---
```
Bearbeitungsstand nicht anzeigen, auch wenn Statusdokumente vorhanden sind.
:::

## Page index

Der Seitenindex ist ein Baum aller speicherbaren Dokumente in der aktuellen Seite.

Im `dev`-Modus wird er automatisch aktualisiert, wenn sich die Seite ändert.

:::details[Page Index]

export const Comp = observer(() => {
const pageStore = useStore('pageStore')

return (
<div style={{ maxHeight: '550px', overflow: 'auto' }}>
<CodeBlock language="json">{JSON.stringify(pageStore._pageIndex, null, 2)}</CodeBlock>
</div>
);
});

<Comp />
:::

## Für Plugin-Autoren

Wenn ein Plugin ein weiteres *Statusdokument* implementiert, das im Seitenindex erfasst werden soll, müssen folgende Schritte durchgeführt werden:
1. In der `siteConfig` die neue Komponente für das `remark`-Plugin registrieren:
```ts title="siteConfig.ts"
import { PageIndexPluginDefaultOptions } from './src/siteConfig/markdownPluginConfigs';
const indexPluginOptions = {
...PageIndexPluginDefaultOptions,
components: [
...PageIndexPluginDefaultOptions.components,
{
name: 'MyNewTaskableDocument',
docTypeExtractor: (node: MdxJsxFlowElement) => 'my_new_taskable_document'
}
]
};
export const pageIndexPluginConfig = [pageIndexPlugin, indexPluginOptions];
```
2. Im `index.ts` des neuen Plugins den neuen Dokumenttyp importieren:
```ts title="packages/<scope>/<new-plugin>/index.ts"
declare module '@tdev-api/document' {
export interface TaskableDocumentMapping {
['my_new_taskable_document']: MyNewTaskableData;
}
export interface TypeModelMapping {
['my_new_taskable_document']: MyNewTaskableDocument;
}
}
```
:::warning[iTaskableDocument]
Das neue `MyNewTaskableDocument`-Modell muss das Interface `iTaskableDocument<'my_new_taskable_document'>` implementieren, damit es im Seitenindex als *Statusdokument* erkannt wird.
:::
3. Im `apiDocumentProviders` den neuen Dokumenttyp registrieren:
```ts title="siteConfig.ts"
const getSiteConfig = () => {
apiDocumentProviders: {
...,
require.resolve('@scope/new-plugin/register')
}
}
```
und den neuen Dokumenttyp im `ComponentStore` registrieren:
```ts title="packages/<scope>/<new-plugin>/register.ts"
const register = () => {
rootStore.componentStore.registerTaskableDocumentType('my_new_taskable_document');
};
```

## Installation

:::info[`docusaurus.config.ts`]
```ts
import pageIndexPlugin from './packages/tdev/page-index/plugin';

export default {
// ...
plugins: [
// ...
pageIndexPlugin
]
};

```
:::

:::info[swizzle `theme/DocSidebarItem/index.tsx`]
See the swizzled component of this page. This should be synced with the `updateTdev.config.yaml` by default.
:::


:::details[remark config]
```ts
import pageProgressStatePlugin from '@tdev/page-index/remark-plugin';

export const PageIndexPluginDefaultOptions: PageIndexPluginOptions = {
components: [
{
name: 'Answer',
docTypeExtractor: (node) => {
return (
getAnswerDocumentType(
node.attributes.find((a) => a.type === 'mdxJsxAttribute' && a.name === 'type')
?.value as string
) || 'unknown'
);
}
},
{
name: 'ProgressState',
docTypeExtractor: () => 'progress_state'
},
{
name: 'TaskState',
docTypeExtractor: () => 'task_state'
},
{
name: 'QuillV2',
docTypeExtractor: () => 'quill_v2'
},
{
name: 'String',
docTypeExtractor: () => 'string'
},
{
name: 'CmsText',
docTypeExtractor: () => 'cms_text'
},
{
name: 'CmsCode',
docTypeExtractor: () => 'cms_text'
},
{
name: 'Restricted',
docTypeExtractor: () => 'restricted'
},
{
name: 'DynamicDocumentRoots',
docTypeExtractor: () => 'dynamic_document_roots'
}
],
persistedCodeType: (node: Code) => {
if (node.lang === 'html') {
return 'script';
}
const liveLangMatch = /(live_[a-zA-Z0-9-_]+)/.exec(node.meta || '');
const liveCode = liveLangMatch ? liveLangMatch[1] : null;

switch (liveCode) {
case 'live_py':
case 'live_bry':
// legacy name, TODO. should be 'brython_code'?
return 'script';
case 'live_pyo':
return 'pyodide_code';
default:
return 'code';
}
}
};
export const pageIndexPluginConfig = [pageIndexPlugin, PageIndexPluginDefaultOptions];
```
:::
51 changes: 51 additions & 0 deletions packages/tdev/page-index/components/TaskableState/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import clsx from 'clsx';
import styles from './styles.module.scss';
import { observer } from 'mobx-react-lite';
import Page from '@tdev-models/Page';
import Icon from '@mdi/react';
import useIsBrowser from '@docusaurus/useIsBrowser';

interface Props {
page?: Page;
className?: string;
forcedAction?: 'show' | 'hide';
}

const TaskableState = observer((props: Props) => {
const { page } = props;
const isBrowser = useIsBrowser();
const forceHide = props.forcedAction === 'hide';
if (forceHide) {
return null;
}

if (!isBrowser || !page) {
return null;
}
const forceShow = props.forcedAction === 'show';

if (!forceShow && page.stepsOnPage === 0 && page.stepsOnDirectSubPages === 0) {
return null;
}

return (
<div
className={clsx(styles.taskableState, props.className)}
title={`Progress: ${page.progress} / ${page.totalSteps}`}
onClick={(e) => {
const thisElement = e.currentTarget;
thisElement.parentElement?.querySelector('a')?.click();
}}
>
<Icon
path={page.editingIconState.path}
size={0.8}
color={page.editingIconState.color}
className={clsx(styles.icon)}
/>
</div>
);
});

export default TaskableState;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.taskableState {
display: flex;
align-items: center;
justify-content: center;
height: 2em;
width: 2em;
cursor: pointer;
border-radius: 1em;
&:hover {
background-color: var(--ifm-hover-overlay);
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading