2 Commits

Author SHA1 Message Date
e5990b9da4 docs: tea-Einrichtung fuer ein frisches Geraet beschreiben
Die Doku stellte fest, tea sei installiert - was auf jedem anderen Geraet
falsch ist und dazu fuehrt, dass saemtliche Kommandos darunter fehlschlagen,
ohne dass der Grund dabeisteht.

Mit dem noetigen Token-Scope, damit gleich klar ist, warum Wartungs-API und
Organisations-Repos nicht funktionieren.
2026-08-28 12:57:26 +02:00
35dbb72cb6 docs: Einstiegspunkt fuer neue Sitzungen in AGENTS.md
Eine Sitzung auf einem anderen Geraet fand bisher zwar die Konventionen und
das Glossar, aber keinen Hinweis darauf, dass es ueberhaupt ein laufendes
Vorhaben gibt - man musste sie jedes Mal von Hand zur Map schicken.

Der Abschnitt nennt keine Issue-Nummer, sondern die Abfrage nach dem Label
wayfinder:map. Damit gilt er auch fuer jede kuenftige Map, ohne gepflegt
werden zu muessen.
2026-08-28 12:56:07 +02:00
10 changed files with 378 additions and 50 deletions

7
.gitignore vendored
View File

@@ -9,9 +9,8 @@
# Dioxus build output # Dioxus build output
/dist /dist
# Node (tailwind toolchain)
node_modules/
# IDE # IDE
/.idea /.idea
# dx erzeugt diese Datei bei jedem vollen Build neu, auch ohne Eingabedatei
# und ohne dass sie noch verlinkt waere. Lokales Nebenprodukt, kein Quellcode.
assets/tailwind.css

View File

@@ -264,6 +264,22 @@ The initial UI rendered by the component on the client must be identical to the
* Use the `use_server_future` hook instead of `use_resource`. It runs the future on the server, serializes the result, and sends it to the client, ensuring the client has the data immediately for its first render. * Use the `use_server_future` hook instead of `use_resource`. It runs the future on the server, serializes the result, and sends it to the client, ensuring the client has the data immediately for its first render.
* Any code that relies on browser-specific APIs (like accessing `localStorage`) must be run *after* hydration. Place this code inside a `use_effect` hook. * Any code that relies on browser-specific APIs (like accessing `localStorage`) must be run *after* hydration. Place this code inside a `use_effect` hook.
## Woran gerade gearbeitet wird
**Bevor du irgendetwas anderes tust:** Laufende Vorhaben liegen als *Wayfinder-Map* im
Issue-Tracker, nicht in diesem Repo. Die offene Map findest du mit
```bash
tea issues ls --labels wayfinder:map --state open
```
Lies ihren Beschreibungstext (Destination, Notes, Decisions so far) **und ihren letzten
Kommentar** — dort steht der Arbeitsstand samt Einstiegspunkt. Erst danach lohnt der Blick
in den Code.
Ist keine Map offen, gibt es kein laufendes Planungsvorhaben; dann gilt die normale
Auftragslage aus dem Gespräch.
## Agent skills ## Agent skills
### Issue tracker ### Issue tracker

View File

@@ -1,32 +1,51 @@
# DioNotes Client # Development
Lokale Markdown-Notizen-App auf Basis von [Dioxus 0.7](https://dioxuslabs.com/learn/0.7), Desktop. Your new bare-bones project includes minimal organization with a single `main.rs` file and a few assets.
## Entwicklung ```
project/
├─ assets/ # Any assets that are used by the app should be placed here
├─ src/
│ ├─ main.rs # main.rs is the entry point to your application and currently contains all components for the app
├─ Cargo.toml # The Cargo.toml file defines the dependencies and feature flags for your project
```
### Automatic Tailwind (Dioxus 0.7+)
As of Dioxus 0.7, there no longer is a need to manually install tailwind. Simply `dx serve` and you're good to go!
Automatic tailwind is supported by checking for a file called `tailwind.css` in your app's manifest directory (next to Cargo.toml). To customize the file, use the dioxus.toml:
```toml
[application]
tailwind_input = "my.css"
tailwind_output = "assets/out.css" # also customize the location of the out file!
```
### Tailwind Manual Install
To use tailwind plugins or manually customize tailwind, you can can install the Tailwind CLI and use it directly.
### Tailwind
1. Install npm: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm
2. Install the Tailwind CSS CLI: https://tailwindcss.com/docs/installation/tailwind-cli
3. Run the following command in the root of the project to start the Tailwind CSS compiler:
```bash ```bash
dx serve # Desktop-App starten (Standard-Plattform) npx @tailwindcss/cli -i ./input.css -o ./assets/tailwind.css --watch
dx serve --platform web # im Browser
cargo test # Tests
``` ```
## Aufbau ### Serving Your App
``` Run the following command in the root of your project to start developing with the default platform:
assets/css/ Design-System: tokens → base → layout → components,
in dieser Reihenfolge in main.rs verlinkt ```bash
src/route.rs alle Routen in einem Routable-Enum dx serve
src/workspace.rs
src/components/ wiederverwendbare Bausteine (CustomLink, CustomButton, …)
src/views/ die Bildschirme: Selector und Editor
docs/ Konventionen für Agenten, Rechercheergebnisse
``` ```
Es gibt **kein** Tailwind und keine npm-Toolchain — das Styling liegt vollständig in To run for a different platform, use the `--platform platform` flag. E.g.
`assets/css/` und arbeitet mit den `--dn-*`-Tokens. ```bash
dx serve --platform desktop
```
## Wo die Entscheidungen liegen
Fachbegriffe stehen in [`CONTEXT.md`](CONTEXT.md). Entscheidungen werden im
Issue-Tracker geführt statt in `docs/adr/`; eine Wayfinder-Map indexiert pro Vorhaben,
welche Entscheidung wo begründet ist. Siehe [`docs/agents/`](docs/agents/).

View File

@@ -4,9 +4,9 @@
Palette: Catppuccin Mocha, matching the editor's Theme::CATPPUCCIN_MOCHA Palette: Catppuccin Mocha, matching the editor's Theme::CATPPUCCIN_MOCHA
so the editor pane and the app chrome are the same surface. so the editor pane and the app chrome are the same surface.
All tokens are prefixed --dn- to keep them in one namespace. The prefix was All tokens are prefixed --dn-. Tailwind v4 publishes its own --font-*,
originally defence against Tailwind v4, which publishes its own --font-*, --text-*, --radius-* and --leading-* on :root and tree-shakes that set as
--text-* and --radius-* on :root; Tailwind is gone, the convention stays. utilities come and go, so an unprefixed token would collide silently.
========================================================================== */ ========================================================================== */
:root { :root {

275
assets/tailwind.css Normal file
View File

@@ -0,0 +1,275 @@
/*! tailwindcss v4.1.5 | MIT License | https://tailwindcss.com */
@layer properties;
@layer theme, base, components, utilities;
@layer theme {
:root, :host {
--font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
monospace;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--leading-tight: 1.25;
--leading-normal: 1.5;
--radius-sm: 0.25rem;
--radius-lg: 0.5rem;
--default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
--default-font-family: var(--font-sans);
--default-mono-font-family: var(--font-mono);
}
}
@layer base {
*, ::after, ::before, ::backdrop, ::file-selector-button {
box-sizing: border-box;
margin: 0;
padding: 0;
border: 0 solid;
}
html, :host {
line-height: 1.5;
-webkit-text-size-adjust: 100%;
tab-size: 4;
font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji');
font-feature-settings: var(--default-font-feature-settings, normal);
font-variation-settings: var(--default-font-variation-settings, normal);
-webkit-tap-highlight-color: transparent;
}
hr {
height: 0;
color: inherit;
border-top-width: 1px;
}
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
h1, h2, h3, h4, h5, h6 {
font-size: inherit;
font-weight: inherit;
}
a {
color: inherit;
-webkit-text-decoration: inherit;
text-decoration: inherit;
}
b, strong {
font-weight: bolder;
}
code, kbd, samp, pre {
font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace);
font-feature-settings: var(--default-mono-font-feature-settings, normal);
font-variation-settings: var(--default-mono-font-variation-settings, normal);
font-size: 1em;
}
small {
font-size: 80%;
}
sub, sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
table {
text-indent: 0;
border-color: inherit;
border-collapse: collapse;
}
:-moz-focusring {
outline: auto;
}
progress {
vertical-align: baseline;
}
summary {
display: list-item;
}
ol, ul, menu {
list-style: none;
}
img, svg, video, canvas, audio, iframe, embed, object {
display: block;
vertical-align: middle;
}
img, video {
max-width: 100%;
height: auto;
}
button, input, select, optgroup, textarea, ::file-selector-button {
font: inherit;
font-feature-settings: inherit;
font-variation-settings: inherit;
letter-spacing: inherit;
color: inherit;
border-radius: 0;
background-color: transparent;
opacity: 1;
}
:where(select:is([multiple], [size])) optgroup {
font-weight: bolder;
}
:where(select:is([multiple], [size])) optgroup option {
padding-inline-start: 20px;
}
::file-selector-button {
margin-inline-end: 4px;
}
::placeholder {
opacity: 1;
}
@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
::placeholder {
color: currentcolor;
@supports (color: color-mix(in lab, red, red)) {
color: color-mix(in oklab, currentcolor 50%, transparent);
}
}
}
textarea {
resize: vertical;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-date-and-time-value {
min-height: 1lh;
text-align: inherit;
}
::-webkit-datetime-edit {
display: inline-flex;
}
::-webkit-datetime-edit-fields-wrapper {
padding: 0;
}
::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
padding-block: 0;
}
:-moz-ui-invalid {
box-shadow: none;
}
button, input:where([type='button'], [type='reset'], [type='submit']), ::file-selector-button {
appearance: button;
}
::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
height: auto;
}
[hidden]:where(:not([hidden='until-found'])) {
display: none !important;
}
}
@layer utilities {
.visible {
visibility: visible;
}
.relative {
position: relative;
}
.static {
position: static;
}
.container {
width: 100%;
@media (width >= 40rem) {
max-width: 40rem;
}
@media (width >= 48rem) {
max-width: 48rem;
}
@media (width >= 64rem) {
max-width: 64rem;
}
@media (width >= 80rem) {
max-width: 80rem;
}
@media (width >= 96rem) {
max-width: 96rem;
}
}
.flex {
display: flex;
}
.table {
display: table;
}
.border-collapse {
border-collapse: collapse;
}
.transform {
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
}
.resize {
resize: both;
}
.border {
border-style: var(--tw-border-style);
border-width: 1px;
}
.text-wrap {
text-wrap: wrap;
}
.underline {
text-decoration-line: underline;
}
.outline {
outline-style: var(--tw-outline-style);
outline-width: 1px;
}
.transition {
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
}
@property --tw-rotate-x {
syntax: "*";
inherits: false;
}
@property --tw-rotate-y {
syntax: "*";
inherits: false;
}
@property --tw-rotate-z {
syntax: "*";
inherits: false;
}
@property --tw-skew-x {
syntax: "*";
inherits: false;
}
@property --tw-skew-y {
syntax: "*";
inherits: false;
}
@property --tw-border-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@property --tw-outline-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop {
--tw-rotate-x: initial;
--tw-rotate-y: initial;
--tw-rotate-z: initial;
--tw-skew-x: initial;
--tw-skew-y: initial;
--tw-border-style: solid;
--tw-outline-style: solid;
}
}
}

View File

@@ -4,7 +4,19 @@ Issues and specs for this repo live as **Gitea** issues at
<https://gitlab.hive-brain.de/RDietermann/dionotes-client>. <https://gitlab.hive-brain.de/RDietermann/dionotes-client>.
> The host is named `gitlab.hive-brain.de`, but the server is **Gitea 1.25.5**, not GitLab. > The host is named `gitlab.hive-brain.de`, but the server is **Gitea 1.25.5**, not GitLab.
> `glab` will not work. Use the [`tea`](https://gitea.com/gitea/tea) CLI (v0.15 installed). > `glab` will not work. Use the [`tea`](https://gitea.com/gitea/tea) CLI (developed against v0.15).
**Auf einem frischen Gerät** ist `tea` erst einzurichten — ohne das schlägt jedes Kommando
unten fehl:
```bash
tea login add --name hive --url https://gitlab.hive-brain.de --token <token>
tea login list # prueft, ob es sitzt
```
Der Token braucht mindestens `write:issue`, `write:repository` und `write:user`. Der hier
verwendete hat **kein** `read:admin` und **kein** `write:organization` — Wartungs-API und
Anlegen unter einer Organisation scheitern damit.
Run `tea` from inside the clone — it resolves owner/repo from `git remote`. It prints Run `tea` from inside the clone — it resolves owner/repo from `git remote`. It prints
`NOTE: no login matched this repository, falling back to login 'hive'` on every call; `NOTE: no login matched this repository, falling back to login 'hive'` on every call;
@@ -61,27 +73,6 @@ Create a Gitea issue.
Run `tea issues <index>` plus `tea comments ls <index>`. Run `tea issues <index>` plus `tea comments ls <index>`.
## Branch- und PR-Workflow
Änderungen werden **nicht direkt auf `main`** committet, sondern auf einem eigenen Branch
pro logischer Einheit — `feat/`, `fix/`, `refactor/`, `chore/`, `docs/`. Eine Einheit ist,
was man in einem Satz begründen kann; wenn die Commit-Nachricht „und außerdem" braucht,
sind es zwei Branches.
Zurück nach `main` geht es über einen **Pull Request in Gitea**, nicht per lokalem Merge:
```bash
git push -u origin <branch>
tea pulls create --title "..." --description "..."
```
`--description` nimmt wie bei Issues nur eine Zeichenkette; für längere Texte eine Datei
schreiben und mit `$(cat datei)` übergeben. Bezieht sich der PR auf ein Ticket, gehört
`Closes #<n>` in die Beschreibung, damit Gitea es beim Mergen schließt.
Gemergt wird in der Weboberfläche — das Mergen ist eine Entscheidung des Menschen, nicht
Teil der Umsetzung.
## Wayfinding operations ## Wayfinding operations
Used by `/wayfinder`. The **map** is a single issue with **child** issues as tickets. Used by `/wayfinder`. The **map** is a single issue with **child** issues as tickets.

18
package-lock.json generated Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "dionotes-client",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"tailwindcss": "^4.3.3"
}
},
"node_modules/tailwindcss": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz",
"integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==",
"license": "MIT"
}
}
}

5
package.json Normal file
View File

@@ -0,0 +1,5 @@
{
"dependencies": {
"tailwindcss": "^4.3.3"
}
}

View File

@@ -17,6 +17,7 @@ const FAVICON: Asset = asset!("/assets/favicon.ico");
// Linked individually rather than via @import in a single entry file: asset!() // Linked individually rather than via @import in a single entry file: asset!()
// only emits files it is given by name, so an @import chain would 404 at runtime. // only emits files it is given by name, so an @import chain would 404 at runtime.
// Order matters — tokens, then baseline, then layout, then components. // Order matters — tokens, then baseline, then layout, then components.
const TAILWIND_CSS: Asset = asset!("/assets/tailwind.css");
const TOKENS_CSS: Asset = asset!("/assets/css/tokens.css"); const TOKENS_CSS: Asset = asset!("/assets/css/tokens.css");
const BASE_CSS: Asset = asset!("/assets/css/base.css"); const BASE_CSS: Asset = asset!("/assets/css/base.css");
const LAYOUT_CSS: Asset = asset!("/assets/css/layout.css"); const LAYOUT_CSS: Asset = asset!("/assets/css/layout.css");
@@ -38,6 +39,9 @@ fn App() -> Element {
rsx! { rsx! {
document::Link { rel: "icon", href: FAVICON } document::Link { rel: "icon", href: FAVICON }
// Tailwind first: its preflight lives in @layer base, our unlayered
// rules win the cascade regardless, but this keeps source order honest.
document::Link { rel: "stylesheet", href: TAILWIND_CSS }
document::Link { rel: "stylesheet", href: TOKENS_CSS } document::Link { rel: "stylesheet", href: TOKENS_CSS }
document::Link { rel: "stylesheet", href: BASE_CSS } document::Link { rel: "stylesheet", href: BASE_CSS }
document::Link { rel: "stylesheet", href: LAYOUT_CSS } document::Link { rel: "stylesheet", href: LAYOUT_CSS }

1
tailwind.css Normal file
View File

@@ -0,0 +1 @@
@import "tailwindcss";