feat: replace Monaco by Ace
All checks were successful
/ pre-commit (push) Successful in 1m30s

- Remove the Monaco Editor because it was to heavy and hard to integrate
- Use Ace instead
- Use the lowercase identifier for languages (ex: "Text" -> "text")
- Select automatically the default language in the drop down to create a note
  (like the expiration)
- Add `ace_directory` to serve assets from a local folder instead of a CDN
- "hcl" syntax highlighting has been removed
- "go" syntax highlighting has been renamed to "golang"

Signed-off-by: Julien Riou <julien@riou.xyz>
This commit is contained in:
Julien Riou 2025-09-21 15:03:39 +02:00
commit 3147306927
Signed by: jriou
GPG key ID: 9A099EDA51316854
8 changed files with 92 additions and 71 deletions

View file

@ -28,6 +28,7 @@ type Config struct {
EnableUploadFileButton bool `json:"enable_upload_file_button"`
TLSCertFile string `json:"tls_cert_file"`
TLSKeyFile string `json:"tls_key_file"`
AceDirectory string `json:"ace_directory"`
BootstrapDirectory string `json:"bootstrap_directory"`
}
@ -56,22 +57,21 @@ func NewConfig() *Config {
PrometheusNotesMetric: "collerd_notes",
ObservationInterval: 60,
Languages: []string{
"Text",
"CSS",
"Dockerfile",
"Go",
"HCL",
"HTML",
"Javascript",
"JSON",
"Markdown",
"Perl",
"Python",
"Ruby",
"Rust",
"Shell",
"SQL",
"YAML",
"css",
"dockerfile",
"golang",
"html",
"javascript",
"json",
"markdown",
"perl",
"python",
"ruby",
"rust",
"sh",
"sql",
"text",
"yaml",
},
Language: "text",
EnableUploadFileButton: true,

View file

@ -21,11 +21,13 @@ type PageData struct {
Version string
Expirations []int
Expiration int
Language string
Languages []string
Err error
URL string
Note *Note
EnableUploadFileButton bool
AceDirectory string
BootstrapDirectory string
}

View file

@ -113,7 +113,9 @@ func (s *Server) Start() error {
Title: s.config.Title,
Expirations: s.config.Expirations,
Expiration: s.config.Expiration,
Language: s.config.Language,
Languages: s.config.Languages,
AceDirectory: s.config.AceDirectory,
BootstrapDirectory: s.config.BootstrapDirectory,
}
@ -159,6 +161,10 @@ func (s *Server) Start() error {
}
r.Path("/{id:[a-zA-Z0-9]+}.html").Handler(webNoteHandler).Methods("GET")
if s.config.AceDirectory != "" {
r.PathPrefix("/static/ace-builds/").Handler(http.StripPrefix("/static/ace-builds/", http.FileServer(http.Dir(s.config.AceDirectory))))
}
if s.config.BootstrapDirectory != "" {
r.PathPrefix("/static/bootstrap/").Handler(http.StripPrefix("/static/bootstrap/", http.FileServer(http.Dir(s.config.BootstrapDirectory))))
}
@ -168,10 +174,10 @@ func (s *Server) Start() error {
addr := fmt.Sprintf("%s:%d", s.config.ListenAddress, s.config.ListenPort)
if s.config.HasTLS() {
s.logger.Info(fmt.Sprintf("listening to %s:%d (https)", s.config.ListenAddress, s.config.ListenPort))
s.logger.Info(fmt.Sprintf("listening to %s:%d", s.config.ListenAddress, s.config.ListenPort), slog.Any("scheme", "http"))
return http.ListenAndServeTLS(addr, s.config.TLSCertFile, s.config.TLSKeyFile, r)
} else {
s.logger.Info(fmt.Sprintf("listening to %s:%d (http)", s.config.ListenAddress, s.config.ListenPort))
s.logger.Info(fmt.Sprintf("listening to %s:%d", s.config.ListenAddress, s.config.ListenPort), slog.Any("scheme", "https"))
return http.ListenAndServe(addr, r)
}
}

View file

@ -40,15 +40,17 @@
<select class="form-select" aria-label="Expiration" id="expiration" name="expiration">
<option disabled>Expiration</option>
{{range $exp := .Expirations}}
<option {{ if eq $exp $.Expiration }}selected="selected"{{end}} value="{{$exp}}">{{HumanDuration $exp}}</option>
<option {{ if eq $exp $.Expiration }}selected="selected" {{end}} value="{{$exp}}">
{{HumanDuration $exp}}</option>
{{end}}
</select>
</div>
<div class="col">
<select class="form-select" aria-label="Language" id="language" name="language">
<option selected="selected" value="" disabled>Language</option>
{{range .Languages}}
<option value="{{lower .}}">{{.}}</option>
<option disabled>Language</option>
{{range $language := .Languages}}
<option {{ if eq $language $.Language }}selected="selected" {{end}}value="{{lower .}}">
{{$language}}</option>
{{end}}
</select>
</div>
@ -69,36 +71,36 @@
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs/loader.min.js"></script>
<script
src="{{if .AceDirectory}}/static/ace-builds{{else}}https://cdn.jsdelivr.net/npm/ace-builds@1.43.3{{end}}/src-noconflict/ace.js"
type="text/javascript" charset="utf-8"></script>
<script>
require.config({ paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs' } });
var editor = ace.edit("editor");
if (document.documentElement.getAttribute('data-bs-theme') == 'light') {
editor.setTheme("ace/theme/github_light_default");
} else {
editor.setTheme("ace/theme/github_dark");
}
require(['vs/editor/editor.main'], function () {
var editor = monaco.editor.create(document.getElementById('editor'), {
theme: document.documentElement.getAttribute('data-bs-theme') == 'light' ? "vs" : "vs-dark",
language: document.getElementById("language").value,
});
// Syntax highlighting
document.getElementById("language").addEventListener("change", (e) => {
if (e.target.value != "") {
editor.getSession().setMode("ace/mode/" + e.target.value);
}
});
// Syntax highlighting
document.getElementById("language").addEventListener("change", (e) => {
if (e.target.value != "") {
monaco.editor.setModelLanguage(editor.getModel(), e.target.value);
}
});
// Dark mode
document.getElementById("lightSwitch").addEventListener("click", () => {
if (document.documentElement.getAttribute('data-bs-theme') == 'light') {
editor.setTheme("ace/theme/github_light_default")
} else if (document.documentElement.getAttribute('data-bs-theme') == 'dark') {
editor.setTheme("ace/theme/github_dark")
}
});
// Dark mode
document.getElementById("lightSwitch").addEventListener("click", () => {
if (document.documentElement.getAttribute('data-bs-theme') == 'light') {
monaco.editor.setTheme("vs")
} else if (document.documentElement.getAttribute('data-bs-theme') == 'dark') {
monaco.editor.setTheme("vs-dark")
}
});
// Copy content on submit
document.getElementById("form").addEventListener("formdata", (e) => {
e.formData.append('content', editor.getModel().getValue());
});
// Copy content on submit
document.getElementById("form").addEventListener("formdata", (e) => {
e.formData.append('content', editor.getValue());
});
</script>
</form>

View file

@ -32,27 +32,31 @@
<div id="editor" name="editor" class="form-control"
style="height: 300px; resize: vertical; overflow: auto;"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs/loader.min.js"></script>
<script
src="{{if .AceDirectory}}/static/ace-builds{{else}}https://cdn.jsdelivr.net/npm/ace-builds@1.43.3{{end}}/src-noconflict/ace.js"
type="text/javascript" charset="utf-8"></script>
<script>
require.config({ paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs' } });
var editor = ace.edit("editor");
editor.setValue("{{string .Note.Content}}");
editor.setReadOnly(true);
editor.getSession().setMode("ace/mode/{{.Note.Language}}");
editor.getSession().selection.clearSelection();
require(['vs/editor/editor.main'], function () {
var editor = monaco.editor.create(document.getElementById('editor'), {
theme: document.documentElement.getAttribute('data-bs-theme') == 'light' ? "vs" : "vs-dark",
language: "{{.Note.Language}}",
readOnly: true,
value: "{{string .Note.Content}}"
});
if (document.documentElement.getAttribute('data-bs-theme') == 'light') {
editor.setTheme("ace/theme/github_light_default");
} else {
editor.setTheme("ace/theme/github_dark");
}
// Dark mode
document.getElementById("lightSwitch").addEventListener("click", () => {
if (document.documentElement.getAttribute('data-bs-theme') == 'light') {
monaco.editor.setTheme("vs")
} else if (document.documentElement.getAttribute('data-bs-theme') == 'dark') {
monaco.editor.setTheme("vs-dark")
}
});
// Dark mode
document.getElementById("lightSwitch").addEventListener("click", () => {
if (document.documentElement.getAttribute('data-bs-theme') == 'light') {
editor.setTheme("ace/theme/github_light_default")
} else if (document.documentElement.getAttribute('data-bs-theme') == 'dark') {
editor.setTheme("ace/theme/github_dark")
}
});
</script>
</div>
{{end}}