mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
- sfs-web (cmd/sfs-web, internal/webapp): read-only Obsidian-style web UI serving a local folder (default) or an sfs remote; markdown rendering with [[wikilinks]], task lists and tables, file downloads with ETags, per-file provenance from the journals; added to goreleaser builds - .sfs project file (internal/config): per-folder volume/remote/include settings that travel with the folder, win over the global registry, and never sync; daemon picks up edits live - .sfsignore + include lists (internal/syncer): gitignore-style selective sync with ! re-includes, applied symmetrically in scan and materialize; newly ignored files stop syncing without being deleted anywhere - Claude Code plugin (plugin/, .claude-plugin/): sfs skill, /sfs:mount and /sfs:status commands, turn-boundary sync hooks (blocking pull on prompt, async push on stop); installable via the repo's marketplace manifest - CLAUDE.md and .claude project settings for Claude Code development Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HHEUaYfFHhmDvqLYw74Ehz
43 lines
1.2 KiB
Go
43 lines
1.2 KiB
Go
package webapp
|
|
|
|
import (
|
|
"bytes"
|
|
"net/url"
|
|
"regexp"
|
|
|
|
"github.com/yuin/goldmark"
|
|
"github.com/yuin/goldmark/extension"
|
|
"github.com/yuin/goldmark/parser"
|
|
)
|
|
|
|
var md = goldmark.New(
|
|
goldmark.WithExtensions(extension.GFM),
|
|
goldmark.WithParserOptions(parser.WithAutoHeadingID()),
|
|
)
|
|
|
|
// wikiRe matches Obsidian-style [[target]] and [[target|label]] links.
|
|
var wikiRe = regexp.MustCompile(`\[\[([^\]|]+)(?:\|([^\]]+))?\]\]`)
|
|
|
|
// expandWikilinks rewrites [[target]] to a markdown link with a wiki: URL;
|
|
// the frontend resolves the target against the file tree by basename.
|
|
func expandWikilinks(src []byte) []byte {
|
|
return wikiRe.ReplaceAllFunc(src, func(m []byte) []byte {
|
|
g := wikiRe.FindSubmatch(m)
|
|
target, label := g[1], g[2]
|
|
if len(label) == 0 {
|
|
label = target
|
|
}
|
|
return []byte("[" + string(label) + "](wiki:" + url.PathEscape(string(target)) + ")")
|
|
})
|
|
}
|
|
|
|
// RenderMarkdown converts markdown to HTML (GFM + wikilinks). Raw HTML in
|
|
// the source is escaped by goldmark's safe default.
|
|
func RenderMarkdown(src []byte) (string, error) {
|
|
var buf bytes.Buffer
|
|
if err := md.Convert(expandWikilinks(src), &buf); err != nil {
|
|
return "", err
|
|
}
|
|
return buf.String(), nil
|
|
}
|