miki

Miki: personal wiki with the fmd markup format
git clone https://wtenison.com/repo/miki.git
Log | Files | Refs | README | LICENSE

commit 9882dee6c3413d794994f0e09ce454f21140cf7b
parent a52fdddf680aeaa4fc21180a749db10aedc85d7b
Author: weetat <wtenison@protonmail.com>
Date:   Sun,  6 Apr 2025 17:40:10 +0000

Move fmd rendering to the client

The server no longer renders fmd. It serves the data directory at
/data/, and the home and subject pages fetch their .fmd files and run
them through the WASM interpreter. Drops the fmd Go dependency.

Diffstat:
Mgo.mod | 2--
Mgo.sum | 2--
Msrc/filesystem/filesystem.go | 4----
Msrc/network/routes.go | 83++++---------------------------------------------------------------------------
Mweb/edit/script.js | 46+++-------------------------------------------
Mweb/global/fmd/wasm_exec.js | 32++++++++++++++++++++++++++++++++
Mweb/global/templates/header.tmpl.html | 2+-
Mweb/home/index.html | 9+++------
Mweb/home/script.js | 110++++---------------------------------------------------------------------------
Mweb/subject/index.html | 11++++-------
Aweb/subject/script.js | 20++++++++++++++++++++
11 files changed, 72 insertions(+), 249 deletions(-)

diff --git a/go.mod b/go.mod @@ -1,5 +1,3 @@ module codeberg.org/wtenison/miki go 1.23.2 - -require codeberg.org/wtenison/fmd v0.0.0-20250313225030-eaad858f680c diff --git a/go.sum b/go.sum @@ -1,2 +0,0 @@ -codeberg.org/wtenison/fmd v0.0.0-20250313225030-eaad858f680c h1:+Qb1bZs+Uxmce7RGiBaic96C6MB23Ow/3G3DHmzxBOU= -codeberg.org/wtenison/fmd v0.0.0-20250313225030-eaad858f680c/go.mod h1:E5rEefleqTyb7LRaUtJQQO1vMJK3f641ym9lUPWHc30= diff --git a/src/filesystem/filesystem.go b/src/filesystem/filesystem.go @@ -11,8 +11,6 @@ var WebGlobalPkg DirectoryPackage func Init() { - //// PULL SYSTEM INFO FROM JSON - var _fsDataStruct struct { DataDirectory string `json:"data-directory"` WebDirectory string `json:"web-directory"` @@ -27,8 +25,6 @@ func Init() { log.Printf("INFO:filesystem:Init:Dirs:%v", Dirs) - //// GET GLOBAL WEB RESOURCES - var _err error WebGlobalPkg, _err = MakeDirectoryPkg(filepath.Join(Dirs["web"], "/global"), SEARCH_DEPTH_INF, "*.html") if _err != nil { diff --git a/src/network/routes.go b/src/network/routes.go @@ -1,15 +1,11 @@ package network import ( - "bytes" "log" "net/http" - "net/url" - "os" "path/filepath" "text/template" - fmd "codeberg.org/wtenison/fmd/src/core" mfs "codeberg.org/wtenison/miki/src/filesystem" ) @@ -22,6 +18,7 @@ func makeServerRoutes() { mux = http.NewServeMux() mux.Handle("/web/", http.StripPrefix("/web/", http.FileServer(http.Dir(mfs.Dirs["web"])))) + mux.Handle("/data/", http.StripPrefix("/data/", http.FileServer(http.Dir(mfs.Dirs["data"])))) mux.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, filepath.Join(mfs.Dirs["web"], "/global/images/favicon.ico")) @@ -62,19 +59,8 @@ func handlePageHome(w http.ResponseWriter, r *http.Request) { return } - _filePath := filepath.Join(mfs.Dirs["data"], "/fmd/home.fmd") - _fileContent, _err := os.ReadFile(_filePath) - if _err != nil { - _fileContent = bytes.NewBufferString("Could not open file.").Bytes() - } - - var _templateDataContainer struct { - FileText string - } - _templateDataContainer.FileText = fmd.InterpretFMDtoHTMLString(string(_fileContent)) - // Render template. - if _err = _tmpl.ExecuteTemplate(w, "index.html", _templateDataContainer); _err != nil { + if _err = _tmpl.ExecuteTemplate(w, "index.html", nil); _err != nil { log.Printf("_ERROR:network:handlePage(\"/home\"):%s", _err) http.Error(w, "_ERROR:network:handlePage(\"/home\"):template.ExecuteTemplate", http.StatusInternalServerError) return @@ -104,39 +90,8 @@ func handlePageSubject(w http.ResponseWriter, r *http.Request) { return } - // Parse URL for query parameters. - _urlContent, _err := url.Parse(r.URL.String()) - if _err != nil { - log.Printf("_ERROR:network:handlePage(\"/subject\"):%s", _err) - http.Error(w, "_ERROR:network:handlePage(\"/subject\"):url.Parse", http.StatusInternalServerError) - } - - _urlQuerySubject, _err := url.ParseQuery(_urlContent.RawQuery) - if _err != nil { - log.Printf("_ERROR:network:handlePage(\"/subject\"):%s", _err) - http.Error(w, "_ERROR:network:handlePage(\"/subject\"):url.ParseQuery", http.StatusInternalServerError) - } - - _fileName := filepath.Base(_urlQuerySubject.Get("s")) - _filePath := filepath.Join(mfs.Dirs["data"], "/fmd/"+_fileName+".fmd") - _fileContent, _err := os.ReadFile(_filePath) - if _err != nil { - _fileContent = bytes.NewBufferString("Could not open file.").Bytes() - } - - // Assign rendered FMD file to buffer. - var _templateDataContainer struct { - FileName string - FileText string - } - _templateDataContainer.FileName = _fileName - _templateDataContainer.FileText = fmd.InterpretFMDtoHTMLString(string(_fileContent)) - if _templateDataContainer.FileText == "" { - _templateDataContainer.FileText = "No File Found" - } - // Render template. - if _err = _tmpl.ExecuteTemplate(w, "index.html", _templateDataContainer); _err != nil { + if _err = _tmpl.ExecuteTemplate(w, "index.html", nil); _err != nil { log.Printf("_ERROR:network:handlePage(\"/subject\"):%s", _err) http.Error(w, "_ERROR:network:handlePage(\"/subject\"):template.ExecuteTemplate", http.StatusInternalServerError) return @@ -158,36 +113,6 @@ func handlePageEdit(w http.ResponseWriter, r *http.Request) { // Add 'global' file dependencies. _rPkg.DependencyFiles = append(_rPkg.DependencyFiles, mfs.WebGlobalPkg.DependencyFiles...) - // Get file name from URL - _urlContent, _err := url.Parse(r.URL.String()) - if _err != nil { - log.Printf("_ERROR:network:handle(\"/edit\"):%s", _err) - http.Error(w, "_ERROR:network:handlePage(\"/edit\"):url.Parse", http.StatusInternalServerError) - } - - // Parse URL for query parameters. - _urlQuerySubject, _err := url.ParseQuery(_urlContent.RawQuery) - if _err != nil { - log.Printf("_ERROR:network:handlePage(\"/edit\"):%s", _err) - http.Error(w, "_ERROR:network:handlePage(\"/edit\"):url.ParseQuery", http.StatusInternalServerError) - } - - _fileName := filepath.Base(_urlQuerySubject.Get("s")) - _filePath := filepath.Join(mfs.Dirs["data"], "/fmd/"+_fileName+".fmd") - _fileContent, _err := os.ReadFile(_filePath) - if _err != nil { - _fileContent = bytes.NewBufferString("Could not open file.").Bytes() - } - - // Extract file content into bufffer. - var _templateDataContainer struct { - FileText string - } - _templateDataContainer.FileText = string(_fileContent) - if _err != nil { - _templateDataContainer.FileText = _err.Error() - } - // Create template from package. _tmpl, _err := template.ParseFiles(_rPkg.DependencyFiles...) if _err != nil { @@ -197,7 +122,7 @@ func handlePageEdit(w http.ResponseWriter, r *http.Request) { } // Render template. - if _err = _tmpl.ExecuteTemplate(w, "index.html", _templateDataContainer); _err != nil { + if _err = _tmpl.ExecuteTemplate(w, "index.html", nil); _err != nil { log.Printf("_ERROR:network:handlePage(\"/edit\"):%s", _err) http.Error(w, "_ERROR:network:handlePage(\"/edit\"):template.ExecuteTemplate", http.StatusInternalServerError) return diff --git a/web/edit/script.js b/web/edit/script.js @@ -12,13 +12,11 @@ WebAssembly.instantiateStreaming(fetch("web/global/fmd/fmd.wasm"), go.importObje .then((result) => { go.run(result.instance); - fmdViewDescriptor.innerHTML = interpretFMD("span(class:\"__descriptor\"):{b:{TEXT PAD}<br>span:{Input fmd text here ▾}}") - // call to FMD function - // isValid = isValidFMD(text_view_content.value) - // update FMD status bar - // updateStatus() + loadFMDFileRaw("https://test.wtenison.com/web/edit/default.fmd", fmdViewPanelSet["text-editor"].content) + + loadFMDFileHTML("https://test.wtenison.com/web/edit/legend.fmd", fmdViewPanelSet["guide-text"].content) }) .catch(err => console.error('_ERROR:instantiateStreaming:failed to load WASM:', err)); @@ -102,44 +100,6 @@ function GotoFrame(nextActiveFrame) { currentFMDView = nextActiveFrame } -// LOAD FMD // - -window.onload = function () { - loadFMDFileRaw("https://test.wtenison.com/web/edit/default.fmd", fmdViewPanelSet["text-editor"].content) - loadFMDFileHTML("https://test.wtenison.com/web/edit/legend.fmd", fmdViewPanelSet["guide-text"].content) -} - -function loadFMDFileRaw(url, container) { - return fetch(url) - .then(response => response.text()) - .then(text => { - // Load the text into the text editor & buffer - _textBUffer = text - }) - .then(() => { - // If FMD is valid, render to HTML - container.innerHTML = _textBUffer - }) -} - -function loadFMDFileHTML(url, container) { - return fetch(url) - .then(response => response.text()) - .then(text => { - // Load the text into the text editor & buffer - _textBUffer = text - }). - then(() => { - // If FMD is valid, render to HTML - if (isValidFMD(_textBUffer)) { - container.innerHTML = interpretFMD(_textBUffer) - } else { - container.innerHTML = "FMD Parsing Failed" - } - }) - .catch(err => console.error('_ERROR:fetch:failed to load FMD url:', err)); -} - document.getElementById("open-guide-bttn").onclick = (event) => { if (!fmdViewPanelSet["guide-text"].root.classList.contains("--open")) { GotoFrame("guide-text") diff --git a/web/global/fmd/wasm_exec.js b/web/global/fmd/wasm_exec.js @@ -539,3 +539,35 @@ }); } })(); + + +function loadFMDFileRaw(url, container) { + return fetch(url) + .then(response => response.text()) + .then(text => { + // Load the text into the text editor & buffer + _textBUffer = text + }) + .then(() => { + // If FMD is valid, render to HTML + container.innerHTML = _textBUffer + }) +} + +function loadFMDFileHTML(url, container) { + return fetch(url) + .then(response => response.text()) + .then(text => { + // Load the text into the text editor & buffer + _textBUffer = text + }). + then(() => { + // If FMD is valid, render to HTML + if (isValidFMD(_textBUffer)) { + container.innerHTML = interpretFMD(_textBUffer) + } else { + container.innerHTML = "FMD Parsing Failed" + } + }) + .catch(err => console.error('_ERROR:fetch:failed to load FMD url:', err)); +} diff --git a/web/global/templates/header.tmpl.html b/web/global/templates/header.tmpl.html @@ -2,7 +2,7 @@ <header class="--center-on-body"> <div id="header-title" class="_content_"><span id="site-name"><i>miki.wtenison</i> :</span> - <span class="--set-size_font-to-screen">{{.}}</span> + <span class="--set-size_font-to-screen"><b>{{.}}</b></span> </div> <nav id="header-nav-view" class="__view __mcol"> diff --git a/web/home/index.html b/web/home/index.html @@ -5,15 +5,14 @@ <title>Miki / Home</title> {{template "meta"}} {{template "fmd"}} + <script src="/web/home/script.js" defer></script> </head> <body> {{template "header" "HOME"}} - <aside id="left-sidebar-view"> - - </aside> + <aside id="left-sidebar-view"></aside> <main class="--center-on-body"> @@ -23,9 +22,7 @@ </main> - <aside id="right-sidebar-view"> - - </aside> + <aside id="right-sidebar-view"></aside> </body> diff --git a/web/home/script.js b/web/home/script.js @@ -6,109 +6,9 @@ WebAssembly.instantiateStreaming(fetch("web/global/fmd/fmd.wasm"), go.importObje .then((result) => { go.run(result.instance); - isValid = isValidFMD(inputText.value) - updateStatus() + _homePageContent = document.getElementById("home-page-view").getElementsByClassName("_content_")[0] - }) - .catch(err => console.error('_ERROR:instantiateStreaming:failed to load WASM:', err)); - -// FMD_VIEW - -isSmall = false -text_view = document.getElementById("text_view") -render_view = document.getElementById("render_view") -swap_view_bttn = document.getElementById("swap_bttn") -let paddingBuffer - -// This determines the view layout for the fmd view area -// between larger and smaller screens. -function mResize() { - if (!isSmall && window.innerWidth <= 750) { - // Set the size of the view elements - text_view.style.width = "100%"; - render_view.style.width = "0%"; - - paddingBuffer = renderView.style.padding; - renderView.style.padding = "0"; - - // Load the swap view button - swap_view_bttn.classList.remove("--hide"); - - // Update state - isSmall = true; - - } else if (isSmall && window.innerWidth > 750) { - // Set the size of the view elements - text_view.style.width = "100%"; - text_view.style.padding = paddingBuffer; - renderView.style.width = "100%"; - renderView.style.padding = paddingBuffer; - - // Hide the swap view button - swap_view_bttn.classList.add("--hide"); - - // Update state - isSmall = false; - } -} - -// When on a small screen, this swaps the viewable element for -// the fmd view area. -function swapView() { - if (isSmall) { - // Swap the width of the views - _bufferWidth = text_view.style.width; - text_view.style.width = render_view.style.width; - render_view.style.width = _bufferWidth; + loadFMDFileHTML("https://test.wtenison.com/data/fmd/home.fmd", _homePageContent) - // Swap the padding of the views - _bufferPadding = text_view.style.padding; - text_view.style.padding = render_view.style.padding; - render_view.style.padding = _bufferPadding; - - // Update the swap button content - _width = parseInt(text_view.style.width) - if (_width == 0) { - swap_view_bttn.innerHTML = "< Return"; - } else { - swap_view_bttn.innerHTML = "Preview >"; - } - } -} - -window.addEventListener("resize", () => { mResize() }) -swap_view_bttn.addEventListener("click", () => { swapView() }) - -// FMD INTERPRETER - -let isValid -inputText = document.getElementById("text_view") -renderView = document.getElementById("render_view") -text_status = document.getElementById("text_status") - -// This updates the fmd status to tell the user if their -// input code is valid or not. -function updateStatus() { - if (isValid) { - text_status.innerHTML = "OK"; - text_status.style.backgroundColor = "var(--color__mint-dark)"; - renderView.innerHTML = interpretFMD(inputText.value) - } else { - text_status.innerHTML = "ERROR" - text_status.style.backgroundColor = "var(--color__red-light)"; - } -} - -inputText.addEventListener('input', (event) => { - isValid = isValidFMD(inputText.value) - - updateStatus() -}) - -window.onload = () => { - // Resizes fmd view window - mResize() - - // Sets the initial text in the fmd text view - inputText.value = "h1:Welcome\nThis is some b:{i:test text}." -} -\ No newline at end of file + }) + .catch(err => console.error('_ERROR:instantiateStreaming:failed to load WASM:', err)); +\ No newline at end of file diff --git a/web/subject/index.html b/web/subject/index.html @@ -5,27 +5,24 @@ <title>Miki / Subject</title> {{template "meta"}} {{template "fmd"}} + <script src="/web/subject/script.js" defer></script> </head> <body> {{template "header" .FileName}} - <aside id="left-sidebar-view"> - - </aside> + <aside id="left-sidebar-view"></aside> <main class="--center-on-body"> - <div id="home-page-view" class="__view"> + <div id="subject-view" class="__view"> <div class="_content_">{{.FileText}}</div> </div> </main> - <aside id="right-sidebar-view"> - - </aside> + <aside id="right-sidebar-view"></aside> </body> diff --git a/web/subject/script.js b/web/subject/script.js @@ -0,0 +1,19 @@ +// START WASM // + +const go = new global.Go(); + +WebAssembly.instantiateStreaming(fetch("web/global/fmd/fmd.wasm"), go.importObject) + .then((result) => { + go.run(result.instance); + _subjectView = document.getElementById("subject-view") + _subjectContent = _subjectView.getElementsByClassName("_content_")[0] + + _urlParams = new URLSearchParams(window.location.search); + const _subject = _urlParams.get("s"); + if (_subject == "") { + _subjectContent.innerHTML = "No subject specified" + } else { + loadFMDFileHTML("https://test.wtenison.com/data/fmd/" + _subject + ".fmd", _subjectContent) + } + }) + .catch(err => console.error('_ERROR:instantiateStreaming:failed to load WASM:', err)); +\ No newline at end of file