From 293d19c04211f0f25598a2e0e338d981b36201ab Mon Sep 17 00:00:00 2001 From: Timna Brown Date: Mon, 13 Apr 2026 08:43:15 -0600 Subject: [PATCH 1/8] Prepare v0.0.1 release pages --- .github/workflows/release-desktop.yml | 28 +- README.md | 49 +- docs/downloads.html | 729 ++++++++++++++++++++++++++ docs/index.html | 340 ++++++++---- 4 files changed, 1011 insertions(+), 135 deletions(-) create mode 100644 docs/downloads.html diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index 80e231b..a15f9f8 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -2,11 +2,18 @@ name: Build Desktop Artifacts on: workflow_dispatch: + inputs: + tag_name: + description: Version tag to build and publish, for example v0.0.2 + required: true + type: string + release_name: + description: Optional release title override + required: false + type: string push: tags: - 'v*' - release: - types: [published] permissions: contents: write @@ -79,7 +86,7 @@ jobs: if-no-files-found: error publish: - if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' || github.event_name == 'release' + if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' needs: build runs-on: ubuntu-latest steps: @@ -95,17 +102,18 @@ jobs: - name: Compute release tag id: release_meta run: | - if [[ "${GITHUB_EVENT_NAME}" == "release" ]]; then - TAG_NAME="${{ github.event.release.tag_name }}" + if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then + TAG_NAME="${{ github.event.inputs.tag_name }}" + RELEASE_NAME="${{ github.event.inputs.release_name }}" echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT" - echo "release_name=Docs Foundry ${TAG_NAME}" >> "$GITHUB_OUTPUT" + if [[ -n "${RELEASE_NAME}" ]]; then + echo "release_name=${RELEASE_NAME}" >> "$GITHUB_OUTPUT" + else + echo "release_name=Docs Foundry ${TAG_NAME}" >> "$GITHUB_OUTPUT" + fi elif [[ "${GITHUB_REF}" == refs/tags/* ]]; then echo "tag_name=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" echo "release_name=Docs Foundry ${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" - else - TAG_NAME="manual-${GITHUB_RUN_NUMBER}" - echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT" - echo "release_name=Docs Foundry ${TAG_NAME}" >> "$GITHUB_OUTPUT" fi - name: Delete existing release if present diff --git a/README.md b/README.md index 51793e8..722a92b 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,14 @@ Last updated: 2026-02-25 For the full changelog and per-version details, see [Releases](https://github.com/Cloud2BR/docs-foundry/releases). +> [!NOTE] +> Desktop releases are published when you push a `v*` tag or when you manually run `.github/workflows/release-desktop.yml` with a `tag_name` input. + ## Roadmap > Git change indicators and diff view, broken-link checks and link autocomplete, PDF export, scroll sync between editor and preview, drag-and-drop file and image support, Mermaid diagram rendering, spell check. -## Two operating modes - -### Mode 1: Container-only development +## Mode 1: Container-only development > This mode is for maintainers and contributors who do not want local Node.js or npm installation. @@ -42,7 +43,7 @@ For the full changelog and per-version details, see [Releases](https://github.co - Builds the dev image. - Installs project dependencies only inside the container. -### Mode 2: End-user desktop app install +## Mode 2: End-user desktop app install > This mode is for users who just want to install and run DocFoundry. @@ -52,37 +53,13 @@ For the full changelog and per-version details, see [Releases](https://github.co Build artifacts go to `release/`. -#### macOS — "damaged and can't be opened" (Gatekeeper) - -DocFoundry is unsigned (no Apple Developer certificate). Use the `.dmg` first when downloading from GitHub Releases. macOS quarantines apps downloaded from the internet. If you open the `.zip` build and macOS blocks it, run this once after downloading: - -```bash -xattr -cr /Applications/DocFoundry.app -``` - -Or if you extracted from the ZIP before moving to Applications: - -```bash -xattr -cr /path/to/DocFoundry.app -``` - -Then double-click the app normally. - -#### Windows — SmartScreen warning - -Click **More info → Run anyway** on the SmartScreen prompt. This appears because the installer is not signed with a code-signing certificate. - -## Build binaries - -### From host machine - -- make package -- make package-mac -- make package-win - -### Linux package build from container +| Platform | Release files | Recommended install path | First-run notes | Build command | +|---|---|---|---|---| +| macOS | `.dmg`, `.zip` | Download the `.dmg` from GitHub Releases and drag `DocFoundry.app` into `Applications`. Use the `.zip` only as a fallback. | The app is unsigned, so Gatekeeper may block the ZIP build. If macOS says the app is damaged, run `xattr -cr /Applications/DocFoundry.app` after moving it to `Applications`, or run `xattr -cr /path/to/DocFoundry.app` on the extracted app bundle before opening it. | `make package-mac` | +| Windows | `NSIS installer`, `.zip` | Use the NSIS installer for the normal install flow. Use the ZIP when you want a manual or portable-style extraction. | Windows SmartScreen may show a warning because the installer is not code-signed. Click **More info → Run anyway** to continue. | `make package-win` | +| Linux | `AppImage`, `.deb`, `.tar.gz` | Use the package format that matches your environment: `AppImage` for portable use, `.deb` for Debian/Ubuntu installs, or `.tar.gz` for manual extraction. | `AppImage` usually needs `chmod +x` before running. For `.deb`, install with `sudo apt install ./DocFoundry.deb` or the generated filename in `release/`. Linux packaging is intended to run from the container workflow. | `make package-linux` | -- make package-linux +For a local multi-platform packaging pass from a compatible host environment, use `make package`. ## GitHub Pages @@ -97,7 +74,7 @@ This repo includes a Pages workflow in `.github/workflows/deploy-pages.yml` and ## Pipelines included - `.github/workflows/deploy-pages.yml`: deploys GitHub Pages. -- `.github/workflows/release-desktop.yml`: builds desktop binaries on macOS, Windows, Linux and publishes on tags. +- `.github/workflows/release-desktop.yml`: builds desktop binaries on macOS, Windows, Linux and publishes a tagged GitHub Release on `v*` tags or manual dispatch with `tag_name`. - `.github/workflows/update-md-date.yml`: updates README date automatically. - `.github/workflows/use-visitor-counter.yml`: updates README visitor badge. - `.github/workflows/cleanup-pages-history.yml`: cleans old Pages workflow runs. @@ -154,7 +131,7 @@ DocFoundry/ ## Quality & Testing -Run code quality checks and tests inside the container: +> Run code quality checks and tests inside the container: ``` make lint # ESLint diff --git a/docs/downloads.html b/docs/downloads.html new file mode 100644 index 0000000..107d1d6 --- /dev/null +++ b/docs/downloads.html @@ -0,0 +1,729 @@ + + + + + + + + Docs Foundry Downloads + + + + + + + +
+
+
+
+

Docs Foundry downloads

+

Install and Use Docs Foundry

+

+ This page keeps the download flow inside GitHub Pages. It shows the latest + published release artifacts, explains how to install them, and gives the + first-run steps for macOS, Windows, and Linux. +

+ +
+ +
+
+
+ +
+
+
+ + +
+ +
+
+

Artifacts

+

Choose your platform

+

+ Each card shows the preferred download first, then the remaining release files + for that platform. Installation notes stay with the relevant operating system. +

+
+
+
+
+ +
+

macOS

+

DMG first, ZIP fallback

+
+
+

+ Best for end users who want the normal drag-to-Applications install flow. +

+
+

Waiting for release assets…

+
+

+ Gatekeeper: install from the .dmg when possible. + If the ZIP build is blocked, run xattr -cr /path/to/DocFoundry.app + once, then reopen it. +

+
+ +
+
+ +
+

Windows

+

NSIS installer first, ZIP fallback

+
+
+

+ Best for Windows users who want a standard installer or a portable ZIP option. +

+
+

Waiting for release assets…

+
+

+ SmartScreen: if Windows shows a warning, click + More info and then Run anyway because the + installer is not code-signed yet. +

+
+ +
+
+ +
+

Linux

+

AppImage, DEB, or TAR.GZ

+
+
+

+ Choose the package style that matches your distro and whether you want a portable build. +

+
+

Waiting for release assets…

+
+

+ Linux tip: AppImage builds usually need chmod +x + before running. DEB builds install cleanly with sudo apt install ./file.deb. +

+
+
+
+ +
+
+

Install guide

+

How to download, install, and use it

+
+
+
+

macOS

+
    +
  1. Download the latest DMG from the macOS card.
  2. +
  3. Open the disk image and drag DocFoundry.app into Applications.
  4. +
  5. If you used the ZIP build and macOS blocks it, run xattr -cr /path/to/DocFoundry.app.
  6. +
  7. Launch the app and open a local documentation folder to start writing.
  8. +
+
+
+

Windows

+
    +
  1. Download the Setup EXE from the Windows card.
  2. +
  3. Run the installer and continue through the normal install wizard.
  4. +
  5. If SmartScreen appears, choose More info and then Run anyway.
  6. +
  7. Start Docs Foundry and open your docs workspace from the sidebar.
  8. +
+
+
+

Linux

+
    +
  1. Choose the artifact that fits your system: AppImage, DEB, or TAR.GZ.
  2. +
  3. For AppImage, run chmod +x DocFoundry.AppImage and open it.
  4. +
  5. For DEB, install with sudo apt install ./file.deb.
  6. +
  7. Launch the app and select a local docs folder to begin editing.
  8. +
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index c345cee..cbcccef 100644 --- a/docs/index.html +++ b/docs/index.html @@ -172,41 +172,108 @@ } /* ── Capability list ── */ - .capability-list { + .section-lead-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - gap: 0; + grid-template-columns: minmax(0, 1.7fr) minmax(280px, 0.9fr); + gap: 18px; + align-items: start; + margin-bottom: 20px; } - .capability-item { + .lead-panel { + border: 1px solid var(--border); + border-radius: var(--radius-lg); + background: linear-gradient(180deg, var(--card), color-mix(in oklab, var(--surface) 45%, var(--card))); + padding: 18px; + } + .lead-panel-title { + margin: 0 0 8px; + font-family: "Space Grotesk", sans-serif; + font-size: 1rem; + } + .lead-panel-copy { + margin: 0; + color: var(--muted); + font-size: 0.92rem; + } + .lead-points { + list-style: none; + padding: 0; + margin: 14px 0 0; + display: grid; + gap: 10px; + } + .lead-points li { display: flex; - gap: 14px; + gap: 10px; align-items: flex-start; - padding: 16px 0; - border-bottom: 1px solid var(--border); + color: var(--muted); + font-size: 0.9rem; } - .capability-item:nth-last-child(-n+2) { - border-bottom: none; + .lead-points strong { + color: var(--fg); + } + .lead-point-mark { + width: 22px; + height: 22px; + border-radius: 999px; + flex-shrink: 0; + display: inline-flex; + align-items: center; + justify-content: center; + background: color-mix(in oklab, var(--link) 18%, var(--card)); + color: var(--link); + font-size: 0.85rem; + font-weight: 700; + margin-top: 1px; } - /* Remove bottom border on last item in each column for even grids */ - @media (min-width: 640px) { - .capability-item:nth-last-child(-n+2) { border-bottom: none; } + .capability-list { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 14px; + } + .capability-item { + display: grid; + grid-template-columns: 48px minmax(0, 1fr); + gap: 14px; + align-items: start; + padding: 18px; + border: 1px solid var(--border); + border-radius: var(--radius-lg); + background: var(--card); + box-shadow: 0 10px 30px color-mix(in oklab, var(--fg) 4%, transparent); } .capability-icon { - font-size: 1.4rem; - flex-shrink: 0; - width: 28px; - text-align: center; - margin-top: 2px; + width: 48px; + height: 48px; + border-radius: 14px; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 1.25rem; + background: color-mix(in oklab, var(--link) 12%, var(--card)); + color: var(--link); + box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--link) 14%, var(--card)); + } + .capability-text { + min-width: 0; + } + .capability-kicker { + display: inline-block; + margin-bottom: 6px; + font-size: 0.72rem; + text-transform: uppercase; + letter-spacing: 0.12em; + color: var(--muted); } .capability-text strong { display: block; - font-size: 0.95rem; - margin-bottom: 3px; + font-size: 1rem; + margin-bottom: 5px; } .capability-text p { margin: 0; color: var(--muted); - font-size: 0.88rem; + font-size: 0.9rem; line-height: 1.5; } @@ -279,10 +346,28 @@ outline-offset: 3px; } .platform-card .platform-icon { - font-size: 2.2rem; - margin-bottom: 10px; + width: 48px; + height: 48px; + margin: 0 auto 12px; + display: inline-flex; + align-items: center; + justify-content: center; + color: var(--fg); + } + .platform-card .platform-icon svg { + width: 100%; + height: 100%; display: block; } + .platform-icon--macos { + color: #111111; + } + .platform-icon--windows { + color: #0f6cbd; + } + .platform-icon--linux { + color: #111111; + } .platform-card h3 { margin: 0 0 4px; font-size: 1.05rem; @@ -305,6 +390,25 @@ font-size: 0.88rem; pointer-events: none; /* card itself is the link */ } + .platform-note { + margin: 14px 0 0; + padding: 10px 12px; + border-radius: 12px; + background: color-mix(in oklab, var(--surface) 72%, var(--card)); + color: var(--muted); + font-size: 0.8rem; + line-height: 1.5; + text-align: left; + } + .platform-note strong { + color: var(--fg); + } + .platform-note code { + background: color-mix(in oklab, var(--surface2) 80%, var(--card)); + padding: 2px 6px; + border-radius: 6px; + font-size: 0.9em; + } .download-row { margin-top: 16px; display: flex; @@ -347,6 +451,20 @@ max-width: 70ch; margin: 6px 0 0; } + .identity-chip { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 10px; + border-radius: 999px; + background: color-mix(in oklab, var(--link) 12%, var(--card)); + color: var(--link); + font-size: 0.76rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + margin-bottom: 10px; + } .identity-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); @@ -434,11 +552,17 @@ /* ── Responsive ── */ @media (max-width: 768px) { + .section-lead-grid { grid-template-columns: 1fr; } + .capability-list { grid-template-columns: 1fr; } .platform-grid { grid-template-columns: 1fr; } .identity-grid { grid-template-columns: 1fr; } .hero h1 { font-size: 1.8rem; } } + @media (min-width: 769px) and (max-width: 1040px) { + .capability-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } + } + @media (prefers-reduced-motion: reduce) { a.platform-card, .download-link-secondary { transition: none; } @@ -482,41 +606,122 @@

Docs Foundry

Getting started

What is Docs Foundry?

-

- Docs Foundry is an open-source desktop application for writing, editing, and - previewing Markdown documentation. Think of it as a lightweight, local-first - docs workspace, purpose-built for documentation projects. -

+
+

+ Docs Foundry is an open-source desktop application for writing, editing, and + previewing Markdown documentation. Think of it as a lightweight, local-first + docs workspace built specifically for documentation projects rather than a + general-purpose IDE. +

+ +
📝 -
Markdown editor

Distraction-free monospace editor with Ctrl+S save and unsaved-change tracking.

+
AuthoringMarkdown editor

Distraction-free monospace editing with fast save, unsaved-change tracking, and a workspace built around docs instead of code noise.

👁️ -
Live preview

Split-pane Markdown rendering in real time — headings, bold, code blocks, lists, and more.

+
FeedbackLive preview

See Markdown render in real time with headings, lists, code blocks, tables, and the formatting details that matter while writing.

📂 -
Sidebar file tree

Open any folder and navigate its full directory structure up to 8 levels deep.

+
NavigationSidebar file tree

Open a docs folder and move through its structure quickly, keeping related markdown, assets, and project files in one place.

🐳 -
Container-first dev

No local Node.js needed. Run make setup to build a Docker container with all deps.

+
ContributingContainer-first dev

No local Node.js required. Run make setup and contributors get the same Docker-based environment with project dependencies inside the container.

📦 -
Cross-platform installers

Native DMG, NSIS, AppImage, and DEB packages built automatically via GitHub Actions.

+
DistributionCross-platform installers

Ship native DMG, NSIS, AppImage, and DEB outputs so people can install the app without building from source.

🔄 -
Auto-update

Packaged builds silently check GitHub Releases for updates via electron-updater.

+
MaintenanceAuto-update

Packaged builds can check GitHub Releases for updates through electron-updater, which keeps distributed installs easier to maintain.

+ +
+ +
+
@@ -554,66 +759,21 @@

Quick start

- -
-
-

For end users

-

Download Docs Foundry

-

- Grab the latest installer for your operating system. Builds are published - automatically to GitHub Releases when a new version tag is pushed. -

- - - - - -

- On macOS, use the .dmg first. If you open the .zip - app bundle and macOS says the app is damaged, run - xattr -cr /path/to/DocFoundry.app once and reopen it. -

-
-
-

Project identity

-

Owner and organization

+

Owner / Organization

- Maintained by the founder and published under Cloud2BR as an open-source - GitHub Pages experience. + Docs Foundry v0.0.1 is presented as an open-source desktop release maintained + by the owner and published through the Cloud2BR organization.

-

Owner / Founder

+

Owner

Owner and organization Cloud2BR

- Open-source tools and community assets published under the Cloud2BR organization. + Cloud2BR is the publishing organization behind the site, release assets, and + open-source project distribution.

-
-

Project context

+
+ v0.0.1 release +

Release context

    -
  • Format: Electron desktop app (HTML, CSS, JS)
  • -
  • Hosting: GitHub Pages for this site, GitHub Releases for binaries
  • -
  • Dev workflow: Container-only (Docker + Makefile)
  • -
  • Purpose: Local-first Markdown documentation workspace
  • +
  • Product: Electron desktop documentation workspace
  • +
  • Release channel: GitHub Releases with tagged binaries and installers
  • +
  • Presentation: GitHub Pages landing site for downloads and project overview
  • +
  • Scope: Initial public release for macOS, Windows, and Linux
From b109f38bc28e49ceb1cc2ef5df82773eec9d16ab Mon Sep 17 00:00:00 2001 From: brown9804 Date: Mon, 13 Apr 2026 09:10:39 -0600 Subject: [PATCH 2/8] Document roadmap and README navigation --- README.md | 123 +++++++++------- docs/index.html | 1 + docs/roadmap.html | 362 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 435 insertions(+), 51 deletions(-) create mode 100644 docs/roadmap.html diff --git a/README.md b/README.md index 722a92b..c77ea3f 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,21 @@ Last updated: 2026-02-25 > DocFoundry is an open-source **Electron** desktop app for writing and previewing Markdown documentation with a live split-pane editor, local folder tree, safe local saves, container-only development for contributors, and installable binaries for macOS, Windows, and Linux. + +
+Table of contents + +- [What's included](#whats-included) +- [Repository tree](#project-structure) +- [Roadmap](#roadmap) +- [Mode 1: Container-only development](#mode-1-container-only-development) +- [Mode 2: End-user desktop app install](#mode-2-end-user-desktop-app-install) +- [GitHub Pages](#github-pages) +- [Pipelines included](#pipelines-included) +- [Quality & Testing](#quality--testing) + +
+ ## What's included > DocFoundry ships multi-tab editing, split-pane live preview, a command palette, workspace-wide search, in-file find and replace, a document outline, file operations (create, rename, delete), auto-save, HTML export, zen mode, resizable panes, a keyboard shortcuts overlay, a status bar (word count, reading time, cursor position), breadcrumbs, and full Markdown rendering (headings, bold/italic, lists, task lists, tables, code blocks, blockquotes, images, links, horizontal rules, strikethrough, highlight, footnotes). The app includes unsaved-change protection on close, a file watcher for external changes, native menus with keyboard accelerators, and a secure architecture (contextIsolation, no nodeIntegration, validated file paths). @@ -19,9 +34,65 @@ For the full changelog and per-version details, see [Releases](https://github.co > [!NOTE] > Desktop releases are published when you push a `v*` tag or when you manually run `.github/workflows/release-desktop.yml` with a `tag_name` input. +
+Expand repository tree + +```text +DocFoundry/ +├── src/ +│ ├── main.js # Electron main process (IPC, menu, file watcher) +│ ├── preload.js # Secure IPC bridge (contextBridge) +│ ├── lib/ +│ │ └── workspace-path.js # Secure path validation +│ └── renderer/ +│ ├── index.html # Desktop app shell (welcome + workspace) +│ ├── styles.css # Full UI styling +│ ├── renderer.js # Tabs, palette, search, outline, editor logic +│ └── markdown.js # Shared Markdown→HTML parser (UMD) +├── build/ +│ ├── icon.svg # App icon source +│ └── generate-icons.sh # SVG to PNG/ICO/ICNS converter +├── docs/ +│ ├── .nojekyll +│ ├── index.html # GitHub Pages overview page +│ ├── downloads.html # Download/install guide backed by GitHub Releases +│ └── roadmap.html # Public roadmap view on GitHub Pages +├── tests/ +│ ├── smoke.test.mjs # Structure, security, and feature-surface tests +│ ├── markdown.test.mjs # Markdown parser tests +│ └── workspace-path.test.mjs # Path validation tests +├── scripts/ +│ └── setup.sh # OS detection and Docker validation +├── .github/ +│ ├── PULL_REQUEST_TEMPLATE.md +│ ├── ISSUE_TEMPLATE/ +│ │ ├── bug_report.md +│ │ └── feature_request.md +│ └── workflows/ +│ ├── deploy-pages.yml +│ ├── release-desktop.yml +│ ├── auto-fill-pr.yml +│ ├── update-md-date.yml +│ ├── update_date.py +│ ├── use-visitor-counter.yml +│ └── cleanup-pages-history.yml +├── Dockerfile.dev # Container dev image (node:20-bookworm) +├── Makefile # setup, dev, lint, format, test, package targets +├── vitest.config.mjs # Vitest configuration +├── eslint.config.mjs # ESLint flat config (v9+) +├── .prettierrc # Prettier configuration +├── CONTRIBUTING.md +├── CODE_OF_CONDUCT.md +├── SECURITY.md +├── LICENSE +└── README.md +``` + +
+ ## Roadmap -> Git change indicators and diff view, broken-link checks and link autocomplete, PDF export, scroll sync between editor and preview, drag-and-drop file and image support, Mermaid diagram rendering, spell check. +Live roadmap page: [Docs Foundry Roadmap](https://cloud2br.github.io/docs-foundry/roadmap.html) ## Mode 1: Container-only development @@ -79,56 +150,6 @@ This repo includes a Pages workflow in `.github/workflows/deploy-pages.yml` and - `.github/workflows/use-visitor-counter.yml`: updates README visitor badge. - `.github/workflows/cleanup-pages-history.yml`: cleans old Pages workflow runs. -## Project structure - -``` -DocFoundry/ -├── src/ -│ ├── main.js # Electron main process (IPC, menu, file watcher) -│ ├── preload.js # Secure IPC bridge (contextBridge) -│ ├── lib/ -│ │ └── workspace-path.js # Secure path validation -│ └── renderer/ -│ ├── index.html # Desktop app shell (welcome + workspace) -│ ├── styles.css # Full UI styling -│ ├── renderer.js # Tabs, palette, search, outline, editor logic -│ └── markdown.js # Shared Markdown→HTML parser (UMD) -├── build/ -│ ├── icon.svg # App icon source -│ └── generate-icons.sh # SVG → PNG/ICO/ICNS converter -├── tests/ -│ ├── smoke.test.mjs # Structure, security & feature-surface tests -│ ├── markdown.test.mjs # Markdown parser tests -│ └── workspace-path.test.mjs # Path validation tests -├── docs/ -│ └── index.html # GitHub Pages landing & download page -├── scripts/ -│ └── setup.sh # OS detection & Docker validation -├── .github/ -│ ├── PULL_REQUEST_TEMPLATE.md -│ ├── ISSUE_TEMPLATE/ -│ │ ├── bug_report.md -│ │ └── feature_request.md -│ └── workflows/ -│ ├── deploy-pages.yml -│ ├── release-desktop.yml -│ ├── auto-fill-pr.yml -│ ├── update-md-date.yml -│ ├── update_date.py -│ ├── use-visitor-counter.yml -│ └── cleanup-pages-history.yml -├── Dockerfile.dev # Container dev image (node:20-bookworm) -├── Makefile # setup, dev, lint, format, test, package targets -├── vitest.config.mjs # Vitest configuration -├── eslint.config.mjs # ESLint flat config (v9+) -├── .prettierrc # Prettier configuration -├── CONTRIBUTING.md -├── CODE_OF_CONDUCT.md -├── SECURITY.md -├── LICENSE -└── README.md -``` - ## Quality & Testing > Run code quality checks and tests inside the container: diff --git a/docs/index.html b/docs/index.html index cbcccef..b860e6f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -714,6 +714,7 @@

Linux

Download guide + Roadmap All releases ↗ Build pipeline ↗ Source on GitHub ↗ diff --git a/docs/roadmap.html b/docs/roadmap.html new file mode 100644 index 0000000..1d1b3bb --- /dev/null +++ b/docs/roadmap.html @@ -0,0 +1,362 @@ + + + + + + + + Docs Foundry Roadmap + + + + + + + +
+
+
+
+

Docs Foundry roadmap

+

What’s Planned Next

+

+ This GitHub Pages view turns the roadmap into a clearer product plan. It keeps + near-term editor improvements, publishing work, and documentation workflow ideas + in one place instead of leaving them as a single long sentence in the README. +

+ +
+ +
+
+
+ +
+
+
+
+

Roadmap overview

+

Current focus areas

+

+ The roadmap is centered on stronger editing workflows, better link and content handling, + and broader export and visualization support for documentation teams. +

+
+
+
+ Editor workflow + Reduce friction while writing +

Focus on diff visibility, synchronized scrolling, and drag-and-drop operations that remove manual steps.

+
+
+ Docs intelligence + Catch issues earlier +

Link validation, autocomplete, and spell checking are aimed at preventing documentation defects before publishing.

+
+
+ Output formats + Support more delivery paths +

PDF export and Mermaid rendering extend the app beyond live preview into shareable and diagram-rich documentation workflows.

+
+
+
+ +
+
+

Planned work

+

Roadmap items

+
+
+
+ Next up +

Editing and review workflow

+

These items improve how writers compare changes, move through documents, and keep preview behavior aligned with the editor.

+
    +
  • Git change indicators and diff view
  • +
  • Scroll sync between editor and preview
  • +
  • Drag-and-drop file and image support
  • +
+
+
+ Planned +

Content quality and navigation

+

These features focus on safer authoring by surfacing broken links, adding faster insertion flows, and improving writing feedback.

+
    +
  • Broken-link checks
  • +
  • Link autocomplete
  • +
  • Spell check
  • +
+
+
+ Planned +

Publishing and output

+

These capabilities extend Docs Foundry beyond editing into richer delivery and sharing paths for documentation teams.

+
    +
  • PDF export
  • +
  • Mermaid diagram rendering
  • +
+
+
+ Planned +

Public roadmap maintenance

+

The roadmap page itself can evolve into a more release-aware planning surface as the project grows.

+
    +
  • Link roadmap items to future releases
  • +
  • Highlight recently shipped features
  • +
  • Group work by release milestone
  • +
+
+
+ +
+
+
+ + + + \ No newline at end of file From 6d34c21a793b600c32873a5e8c27126461a9e00b Mon Sep 17 00:00:00 2001 From: brown9804 Date: Mon, 13 Apr 2026 09:10:39 -0600 Subject: [PATCH 3/8] Add editor workflow features for v0.0.1 --- src/main.js | 146 +++++++++++- src/preload.js | 9 + src/renderer/index.html | 28 ++- src/renderer/markdown.js | 3 + src/renderer/renderer.js | 490 ++++++++++++++++++++++++++++++++++++++- src/renderer/styles.css | 123 ++++++++++ tests/markdown.test.mjs | 7 + tests/smoke.test.mjs | 50 ++++ 8 files changed, 851 insertions(+), 5 deletions(-) diff --git a/src/main.js b/src/main.js index b65c1ea..1e5ef64 100644 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,8 @@ const { app, BrowserWindow, ipcMain, dialog, Menu } = require('electron'); const path = require('path'); const fs = require('fs'); +const os = require('os'); +const { execFileSync } = require('child_process'); const { resolveWorkspacePath, validateFileName } = require('./lib/workspace-path'); // Hot reload in development @@ -36,7 +38,8 @@ function createWindow() { webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, - nodeIntegration: false + nodeIntegration: false, + spellcheck: true } }); @@ -70,6 +73,7 @@ function buildAppMenu() { { type: 'separator' }, { label: 'Save', accelerator: 'CmdOrCtrl+S', click: () => mainWindow.webContents.send('menu-save') }, { label: 'Export HTML…', accelerator: 'CmdOrCtrl+Shift+E', click: () => mainWindow.webContents.send('menu-export-html') }, + { label: 'Export PDF…', accelerator: 'CmdOrCtrl+Shift+P', click: () => mainWindow.webContents.send('menu-export-pdf') }, { type: 'separator' }, isMac ? { role: 'close' } : { role: 'quit' } ] @@ -93,6 +97,8 @@ function buildAppMenu() { submenu: [ { label: 'Command Palette…', accelerator: 'CmdOrCtrl+P', click: () => mainWindow.webContents.send('menu-command-palette') }, { label: 'Workspace Search…', accelerator: 'CmdOrCtrl+Shift+F', click: () => mainWindow.webContents.send('menu-workspace-search') }, + { label: 'Git Diff…', accelerator: 'CmdOrCtrl+Shift+D', click: () => mainWindow.webContents.send('menu-git-diff') }, + { label: 'Check Broken Links…', accelerator: 'CmdOrCtrl+Shift+L', click: () => mainWindow.webContents.send('menu-check-links') }, { type: 'separator' }, { label: 'Toggle Sidebar', accelerator: 'CmdOrCtrl+B', click: () => mainWindow.webContents.send('menu-toggle-sidebar') }, { label: 'Toggle Outline', accelerator: 'CmdOrCtrl+Shift+O', click: () => mainWindow.webContents.send('menu-toggle-outline') }, @@ -366,6 +372,110 @@ ipcMain.handle('export-html', async (_event, htmlContent, suggestedName) => { return true; }); +ipcMain.handle('export-pdf', async (_event, htmlContent, suggestedName) => { + if (!mainWindow) return false; + + const result = await dialog.showSaveDialog(mainWindow, { + title: 'Export PDF', + defaultPath: suggestedName || 'document.pdf', + filters: [{ name: 'PDF Files', extensions: ['pdf'] }] + }); + if (result.canceled || !result.filePath) return false; + + const pdfWindow = new BrowserWindow({ + show: false, + webPreferences: { + sandbox: true, + contextIsolation: true, + nodeIntegration: false + } + }); + + const fullHtml = `${htmlContent}`; + + try { + await pdfWindow.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(fullHtml)}`); + const pdf = await pdfWindow.webContents.printToPDF({ printBackground: true, preferCSSPageSize: true }); + fs.writeFileSync(result.filePath, pdf); + return true; + } finally { + if (!pdfWindow.isDestroyed()) { + pdfWindow.destroy(); + } + } +}); + +ipcMain.handle('get-git-status', async () => { + const repoRoot = findGitRoot(currentFolder); + if (!repoRoot) return { available: false, repoRoot: null, entries: [] }; + + try { + const output = execFileSync('git', ['-C', repoRoot, 'status', '--porcelain', '--untracked-files=all'], { + encoding: 'utf-8' + }); + const entries = output + .split('\n') + .filter(Boolean) + .map(line => parseGitStatusLine(line, repoRoot)); + + return { available: true, repoRoot, entries }; + } catch (_) { + return { available: false, repoRoot, entries: [] }; + } +}); + +ipcMain.handle('get-git-diff', async (_event, filePath) => { + const repoRoot = findGitRoot(currentFolder); + if (!repoRoot || !filePath) return { available: false, diff: '', status: 'unavailable' }; + + const resolved = resolveWorkspacePath(currentFolder, filePath); + const relative = path.relative(repoRoot, resolved); + + try { + const statusOutput = execFileSync('git', ['-C', repoRoot, 'status', '--porcelain', '--', relative], { + encoding: 'utf-8' + }).trim(); + const status = statusOutput ? statusOutput.slice(0, 2).trim() || '?' : 'clean'; + + let diff = execFileSync('git', ['-C', repoRoot, 'diff', '--no-color', '--', relative], { + encoding: 'utf-8' + }); + + if (!diff.trim() && status === '??') { + const content = fs.readFileSync(resolved, 'utf-8'); + diff = `Untracked file: ${relative}${os.EOL}${os.EOL}${content}`; + } + + return { available: true, diff, status, repoRoot, relativePath: relative }; + } catch (error) { + return { available: false, diff: '', status: 'error', message: error.message }; + } +}); + +ipcMain.handle('import-files-into-workspace', async (_event, sources, targetDir) => { + if (!Array.isArray(sources) || sources.length === 0) return []; + const resolvedDir = resolveWorkspacePath(currentFolder, targetDir || currentFolder); + fs.mkdirSync(resolvedDir, { recursive: true }); + + return sources.map(sourcePath => { + const sourceName = path.basename(sourcePath); + const targetPath = createAvailablePath(resolvedDir, sourceName); + fs.copyFileSync(sourcePath, targetPath); + + return { + sourcePath, + path: targetPath, + name: path.basename(targetPath), + relativePath: currentFolder ? path.relative(currentFolder, targetPath) : path.basename(targetPath), + isImage: /\.(png|jpe?g|gif|webp|svg)$/i.test(targetPath) + }; + }); +}); + // ── IPC: prompt for new file/folder name ────────────────────────────────────── ipcMain.handle('prompt-new-file', async (_event, parentDir) => { @@ -441,6 +551,40 @@ function readFolderTree(rootPath) { return { root: rootPath, name: path.basename(rootPath), children: walk(rootPath, 0) }; } +function findGitRoot(startPath) { + if (!startPath) return null; + try { + return execFileSync('git', ['-C', startPath, 'rev-parse', '--show-toplevel'], { + encoding: 'utf-8' + }).trim(); + } catch (_) { + return null; + } +} + +function parseGitStatusLine(line, repoRoot) { + const status = line.slice(0, 2); + const filePath = line.slice(3).trim(); + return { + status, + path: path.join(repoRoot, filePath), + relativePath: filePath + }; +} + +function createAvailablePath(dirPath, fileName) { + const parsed = path.parse(fileName); + let candidate = path.join(dirPath, fileName); + let counter = 1; + + while (fs.existsSync(candidate)) { + candidate = path.join(dirPath, `${parsed.name}-${counter}${parsed.ext}`); + counter += 1; + } + + return candidate; +} + // ── App lifecycle ───────────────────────────────────────────────────────────── app.whenReady().then(() => { diff --git a/src/preload.js b/src/preload.js index 5bf4d8f..5caeab8 100644 --- a/src/preload.js +++ b/src/preload.js @@ -26,6 +26,14 @@ contextBridge.exposeInMainWorld('docfoundry', { // Export exportHtml: (htmlContent, suggestedName) => ipcRenderer.invoke('export-html', htmlContent, suggestedName), + exportPdf: (htmlContent, suggestedName) => ipcRenderer.invoke('export-pdf', htmlContent, suggestedName), + + // Git + getGitStatus: () => ipcRenderer.invoke('get-git-status'), + getGitDiff: (filePath) => ipcRenderer.invoke('get-git-diff', filePath), + + // File import + importFilesIntoWorkspace: (sources, targetDir) => ipcRenderer.invoke('import-files-into-workspace', sources, targetDir), // Dirty state setDirtyState: (isDirty) => ipcRenderer.send('set-dirty-state', isDirty), @@ -38,6 +46,7 @@ contextBridge.exposeInMainWorld('docfoundry', { onMenuEvent: (channel, callback) => { const validChannels = [ 'menu-open-folder', 'menu-new-file', 'menu-save', 'menu-export-html', + 'menu-export-pdf', 'menu-git-diff', 'menu-check-links', 'menu-find', 'menu-replace', 'menu-command-palette', 'menu-workspace-search', 'menu-toggle-sidebar', 'menu-toggle-outline', 'menu-zen-mode', 'menu-shortcuts' ]; diff --git a/src/renderer/index.html b/src/renderer/index.html index b4fe136..e3013ea 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -3,7 +3,7 @@ - + DocFoundry @@ -126,7 +126,8 @@

Export

- + +
@@ -168,6 +169,26 @@

Export

+ + + +
@@ -711,15 +768,6 @@

Linux

↓ Download for Linux - -
- Download guide - Roadmap - All releases ↗ - Build pipeline ↗ - Source on GitHub ↗ -
- diff --git a/docs/roadmap.html b/docs/roadmap.html index fe6d5df..9fab718 100644 --- a/docs/roadmap.html +++ b/docs/roadmap.html @@ -239,15 +239,16 @@

Docs Foundry roadmap

-

Roadmap and Release Progress

+

v0.0.1 Roadmap and Release Progress

- This GitHub Pages view tracks what shipped in v0.0.1 and what the project can - prioritize next. It keeps release progress and future planning in one place instead - of leaving everything as a single sentence in the README. + This GitHub Pages view keeps shipped work separate from upcoming work and presents + the forward plan with ETA-style product signals, similar to how many ISVs present a + public roadmap.

@@ -259,8 +260,8 @@

Roadmap and Release Progress

-

v0.0.1 delivered

-

Recently shipped capabilities

+

Already in v0.0.1

+

Shipped and validated

These capabilities are now part of the current DocFoundry desktop experience and should no longer be treated as roadmap-only items. @@ -287,16 +288,16 @@

Recently shipped capabilities

-

Next planning areas

-

What comes after v0.0.1

+

Product roadmap

+

ETA for upcoming features

- With the v0.0.1 editing workflow items shipped, the next roadmap can focus on stronger publishing, - collaboration, and release planning rather than the features already delivered. + This forward-looking roadmap keeps the shipped work above and uses ETA-style windows + for the next feature areas people can expect to see evolve.

- Next up + ETA: Apr-May 2026

Publishing workflow

These items extend DocFoundry beyond editing into fuller documentation publishing and release packaging flows.

    @@ -306,7 +307,7 @@

    Publishing workflow

- Planned + ETA: May 2026

Workspace intelligence

These features deepen the current authoring flow by helping users reason about structure, references, and document quality at scale.

    @@ -316,7 +317,7 @@

    Workspace intelligence

- Planned + ETA: Jun 2026

Team collaboration

These items move the product closer to shared documentation workflows without turning it into a full IDE.

    @@ -326,9 +327,9 @@

    Team collaboration

- Planned + ETA: Ongoing

Public roadmap maintenance

-

The roadmap page itself can evolve into a more release-aware planning surface as the project grows.

+

The roadmap should stay current, release-aware, and transparent as new features ship and priorities shift.

  • Link roadmap items to future releases
  • Highlight recently shipped features
  • @@ -337,10 +338,43 @@

    Public roadmap maintenance

+ +
+
+

Feedback channel

+

Tell us what to add or improve

+

+ The feedback flow is designed so requests can be saved as GitHub issues in a separate + feedback repo instead of landing in the main source repository. That keeps product + requests visible without blocking release work or protected branches. +

+
+
+
+ Features + Request something new +

Send a feature request for a capability, workflow, integration, or platform improvement.

+
+
+ Improvements + Refine what exists +

Submit improvements for current workflows such as exports, navigation, preview quality, or packaging.

+
+
+ Docs & roadmap + Improve communication +

Share onboarding gaps, documentation fixes, roadmap feedback, and prioritization suggestions.

+
+
+ +
diff --git a/eslint.config.mjs b/eslint.config.mjs index b633a2f..bab2d4a 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -14,6 +14,10 @@ export default [ localStorage: 'readonly', CSS: 'readonly', console: 'readonly', + setTimeout: 'readonly', + clearTimeout: 'readonly', + queueMicrotask: 'readonly', + URL: 'readonly', // node require: 'readonly', module: 'readonly', diff --git a/src/lib/workspace-path.js b/src/lib/workspace-path.js index 12e7fb0..7746589 100644 --- a/src/lib/workspace-path.js +++ b/src/lib/workspace-path.js @@ -1,9 +1,19 @@ const path = require('path'); const fs = require('fs'); -const INVALID_NAME_CHARS = /[\x00-\x1f<>:"|?*]/; +const INVALID_NAME_CHARS = /[<>:"|?*]/; const WINDOWS_RESERVED = /^(con|prn|aux|nul|com\d|lpt\d)$/i; +function hasControlCharacters(value) { + for (const character of value) { + const codePoint = character.codePointAt(0); + if (typeof codePoint === 'number' && codePoint <= 31) { + return true; + } + } + return false; +} + function resolveWorkspacePath(workspaceRoot, candidatePath) { const resolvedPath = path.resolve(candidatePath); if (!workspaceRoot) return resolvedPath; @@ -53,7 +63,7 @@ function validateFileName(name) { if (trimmed !== name || trimmed.endsWith('.') || trimmed.endsWith(' ')) { throw new Error('File name has invalid leading/trailing characters'); } - if (INVALID_NAME_CHARS.test(trimmed)) { + if (hasControlCharacters(trimmed) || INVALID_NAME_CHARS.test(trimmed)) { throw new Error('File name contains invalid characters'); } if (trimmed.includes('/') || trimmed.includes('\\')) { diff --git a/src/main.js b/src/main.js index 1e5ef64..eb78c75 100644 --- a/src/main.js +++ b/src/main.js @@ -23,6 +23,16 @@ let hasUnsavedChanges = false; let allowWindowClose = false; let fileWatcher = null; +function hasControlCharacters(value) { + for (const character of value) { + const codePoint = character.codePointAt(0); + if (typeof codePoint === 'number' && codePoint <= 31) { + return true; + } + } + return false; +} + function createWindow() { allowWindowClose = false; hasUnsavedChanges = false; @@ -497,13 +507,13 @@ function startFileWatcher(folderPath) { try { fileWatcher = fs.watch(folderPath, { recursive: true }, (eventType, fileName) => { if (!fileName) return; - // Sanitize: reject null bytes and control characters - if (/[\x00-\x1f]/.test(fileName)) return; + const normalizedFileName = String(fileName); + if (hasControlCharacters(normalizedFileName)) return; const IGNORE_PATTERNS = ['.git', 'node_modules', '.DS_Store']; - if (IGNORE_PATTERNS.some(p => fileName.includes(p))) return; + if (IGNORE_PATTERNS.some(p => normalizedFileName.includes(p))) return; if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.webContents.send('workspace-changed', { eventType, fileName: String(fileName) }); + mainWindow.webContents.send('workspace-changed', { eventType, fileName: normalizedFileName }); } }); } catch (_) { diff --git a/src/renderer/index.html b/src/renderer/index.html index 4cd25ca..6eb8b37 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -52,7 +52,7 @@

Organize

Export

-

Export your rendered documents to standalone HTML files.

+

Export your rendered documents to standalone HTML or PDF files.

diff --git a/src/renderer/markdown.js b/src/renderer/markdown.js index 46d1d76..acc9ba4 100644 --- a/src/renderer/markdown.js +++ b/src/renderer/markdown.js @@ -199,7 +199,7 @@ const header = lines[index].trim(); const separator = lines[index + 1].trim(); - return header.includes('|') && /^\|?\s*[:\-]+(?:\s*\|\s*[:\-]+)+\s*\|?$/.test(separator); + return header.includes('|') && /^\|?\s*[:-]+(?:\s*\|\s*[:-]+)+\s*\|?$/.test(separator); } function renderTable(lines, startIndex) { @@ -299,7 +299,7 @@ } function escapeHtml(text) { - return text.replace(/[&<>\"]/g, char => { + return text.replace(/[&<>"]/g, char => { const entities = { '&': '&', '<': '<', diff --git a/src/renderer/renderer.js b/src/renderer/renderer.js index a51ab31..30f2234 100644 --- a/src/renderer/renderer.js +++ b/src/renderer/renderer.js @@ -321,17 +321,15 @@ codeEditor.addEventListener('keydown', (e) => { if (e.shiftKey) { // Outdent: remove leading two spaces from each selected line const before = value.substring(0, start); - const selected = value.substring(start, end); const lineStart = before.lastIndexOf('\n') + 1; const block = value.substring(lineStart, end); - const outdented = block.replace(/^ /gm, ''); + const outdented = block.replace(/^ {2}/gm, ''); codeEditor.value = value.substring(0, lineStart) + outdented + value.substring(end); codeEditor.selectionStart = start - (block.length - outdented.length > 0 ? Math.min(2, start - lineStart) : 0); codeEditor.selectionEnd = lineStart + outdented.length; } else if (start !== end) { // Indent selected lines const before = value.substring(0, start); - const selected = value.substring(start, end); const lineStart = before.lastIndexOf('\n') + 1; const block = value.substring(lineStart, end); const indented = block.replace(/^/gm, ' '); diff --git a/tests/smoke.test.mjs b/tests/smoke.test.mjs index a303f84..4e9876e 100644 --- a/tests/smoke.test.mjs +++ b/tests/smoke.test.mjs @@ -75,7 +75,8 @@ describe('Security', () => { it('file watcher sanitizes file names', () => { const main = fs.readFileSync(path.resolve('src/main.js'), 'utf-8'); - expect(main).toContain('[\\x00-\\x1f]'); + expect(main).toContain('function hasControlCharacters(value)'); + expect(main).toContain('codePoint <= 31'); }); it('main process tracks dirty editor state', () => { From e7a93d688324cc0bc6c63cbe8a4dbe555124482f Mon Sep 17 00:00:00 2001 From: Timna Brown <24630902+brown9804@users.noreply.github.com> Date: Mon, 13 Apr 2026 12:29:21 -0600 Subject: [PATCH 7/8] Update README to remove v0.0.1 feature details Removed redundant information about version v0.0.1 features. --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5be28e3..34ad3f1 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,6 @@ Last updated: 2026-02-25 > DocFoundry ships multi-tab editing, split-pane live preview, a command palette, workspace-wide search, in-file find and replace, a document outline, file operations (create, rename, delete), auto-save, HTML export, zen mode, resizable panes, a keyboard shortcuts overlay, a status bar (word count, reading time, cursor position), breadcrumbs, and full Markdown rendering (headings, bold/italic, lists, task lists, tables, code blocks, blockquotes, images, links, horizontal rules, strikethrough, highlight, footnotes). The app includes unsaved-change protection on close, a file watcher for external changes, native menus with keyboard accelerators, and a secure architecture (contextIsolation, no nodeIntegration, validated file paths). -> v0.0.1 also includes Git change indicators with per-file diff view, broken-link checks, link autocomplete, PDF export, editor/preview scroll sync, drag-and-drop file and image support, Mermaid diagram rendering from a bundled local asset, and native spell check. - For the full changelog and per-version details, see [Releases](https://github.com/Cloud2BR/docs-foundry/releases). > [!NOTE] @@ -98,7 +96,8 @@ DocFoundry/ Live roadmap page: [Docs Foundry Roadmap](https://cloud2br.github.io/docs-foundry/roadmap.html) Product feedback page: [Docs Foundry Feedback](https://cloud2br.github.io/docs-foundry/feedback.html) -The feedback page prepopulates requests in the GitHub Pages UI and routes them into [Cloud2BR/docs-foundry-feedback](https://github.com/Cloud2BR/docs-foundry-feedback). The production flow opens a prefilled issue there and lets that repo process it with a GitHub Actions intake workflow after submission. +> [!IMPORTANT] +> The feedback page prepopulates requests in the GitHub Pages UI and routes them into [Cloud2BR/docs-foundry-feedback](https://github.com/Cloud2BR/docs-foundry-feedback). The production flow opens a prefilled issue there and lets that repo process it with a GitHub Actions intake workflow after submission. ## Mode 1: Container-only development From 3835cab66b073857840329b8de22d88adecbadc9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 18:30:27 +0000 Subject: [PATCH 8/8] docs: update visitor count --- CODE_OF_CONDUCT.md | 2 +- CONTRIBUTING.md | 2 +- README.md | 2 +- SECURITY.md | 2 +- docs/index.html | 2 +- metrics.json | 13 +++++++++---- 6 files changed, 14 insertions(+), 9 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 20e9d4e..cf23a5f 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -40,7 +40,7 @@ This Code of Conduct is adapted from the [Contributor Covenant](https://www.cont
- Total views + Total views

Refresh Date: 2026-04-13

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8533149..7a46785 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -82,7 +82,7 @@ Open an issue on GitHub with reproduction steps. Include OS, app version, and an
- Total views + Total views

Refresh Date: 2026-04-13

diff --git a/README.md b/README.md index 34ad3f1..346f199 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ make test # Vitest
- Total views + Total views

Refresh Date: 2026-04-13

diff --git a/SECURITY.md b/SECURITY.md index b8f7b8c..46c31be 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -37,7 +37,7 @@ If you discover a security vulnerability in DocFoundry, please report it respons
- Total views + Total views

Refresh Date: 2026-04-13

diff --git a/docs/index.html b/docs/index.html index aedfe6e..5231d9e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -614,7 +614,7 @@

Docs Foundry

Build Desktop Artifacts status - Total views + Total views
diff --git a/metrics.json b/metrics.json index 8963073..61c28be 100644 --- a/metrics.json +++ b/metrics.json @@ -66,12 +66,17 @@ }, { "date": "2026-04-11", - "count": 2, - "uniques": 2 + "count": 0, + "uniques": 0 }, { "date": "2026-04-12", - "count": 1, - "uniques": 1 + "count": 0, + "uniques": 0 + }, + { + "date": "2026-04-13", + "count": 0, + "uniques": 0 } ] \ No newline at end of file