Add new note prompt
This commit is contained in:
parent
7830ae3217
commit
20ca509a2b
8 changed files with 45 additions and 8 deletions
|
@ -1,6 +1,14 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
This file keeps track of changes in more human-readable fashion
|
This file keeps track of changes in more human-readable fashion
|
||||||
|
|
||||||
|
## v0.5.0
|
||||||
|
* Added a JS prompt to create new note
|
||||||
|
* "Sanitization" for this method is basic and assumes a well-meaning user
|
||||||
|
* Old instructions appear if JS is disabled
|
||||||
|
* Bug fixes
|
||||||
|
* Non-latin note names are now rendered correctly
|
||||||
|
* Config reload now sets removed values to defaults
|
||||||
|
|
||||||
## v0.4.0
|
## v0.4.0
|
||||||
* Customisation changes
|
* Customisation changes
|
||||||
* Added `title` option to config
|
* Added `title` option to config
|
||||||
|
|
|
@ -76,6 +76,8 @@ func (c *Config) Save() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Reload() error {
|
func (c *Config) Reload() error {
|
||||||
|
*c = DefaultConfig // Reset config
|
||||||
|
|
||||||
if _, err := os.Stat(ConfigFile); errors.Is(err, os.ErrNotExist) {
|
if _, err := os.Stat(ConfigFile); errors.Is(err, os.ErrNotExist) {
|
||||||
err := c.Save()
|
err := c.Save()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -156,7 +158,7 @@ func (c *Config) Reload() error {
|
||||||
|
|
||||||
// ConfigInit loads config on startup
|
// ConfigInit loads config on startup
|
||||||
func ConfigInit() Config {
|
func ConfigInit() Config {
|
||||||
cfg := DefaultConfig
|
cfg := Config{}
|
||||||
err := cfg.Reload()
|
err := cfg.Reload()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|
|
@ -12,10 +12,12 @@
|
||||||
"link.notes": "notes",
|
"link.notes": "notes",
|
||||||
"link.info": "app information",
|
"link.info": "app information",
|
||||||
|
|
||||||
"description.notes": "/notes/<name> for a new note",
|
|
||||||
"time.date": "Today is",
|
"time.date": "Today is",
|
||||||
"time.grace": "grace period active",
|
"time.grace": "grace period active",
|
||||||
"button.save": "Save",
|
"button.save": "Save",
|
||||||
|
"button.notes": "New note",
|
||||||
|
"prompt.notes": "Note name",
|
||||||
|
"noscript.notes": "/notes/<name>",
|
||||||
|
|
||||||
"info.version": "Version",
|
"info.version": "Version",
|
||||||
"info.version.link": "source and changelog",
|
"info.version.link": "source and changelog",
|
||||||
|
|
|
@ -12,10 +12,12 @@
|
||||||
"link.notes": "заметки",
|
"link.notes": "заметки",
|
||||||
"link.info": "системная информация",
|
"link.info": "системная информация",
|
||||||
|
|
||||||
"description.notes": "/notes/<название> для новой заметки",
|
|
||||||
"time.date": "Сегодня",
|
"time.date": "Сегодня",
|
||||||
"time.grace": "льготный период",
|
"time.grace": "льготный период",
|
||||||
"button.save": "Сохранить",
|
"button.save": "Сохранить",
|
||||||
|
"button.notes": "Новая заметка",
|
||||||
|
"prompt.notes": "Название заметки",
|
||||||
|
"noscript.notes": "/notes/<название>",
|
||||||
|
|
||||||
"info.version": "Версия",
|
"info.version": "Версия",
|
||||||
"info.version.link": "исходный код",
|
"info.version.link": "исходный код",
|
||||||
|
|
2
info.go
2
info.go
|
@ -15,7 +15,7 @@ type AppInfo struct {
|
||||||
|
|
||||||
// Info contains app information
|
// Info contains app information
|
||||||
var Info = AppInfo{
|
var Info = AppInfo{
|
||||||
Version: "0.4.0",
|
Version: "0.5.0",
|
||||||
SourceLink: "https://git.a71.su/Andrew71/hibiscus",
|
SourceLink: "https://git.a71.su/Andrew71/hibiscus",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<link rel="icon" type="image/x-icon" href="/public/favicon.ico">
|
<link rel="icon" type="image/x-icon" href="/public/favicon.ico">
|
||||||
<link rel="stylesheet" href="/public/main.css">
|
<link rel="stylesheet" href="/public/main.css">
|
||||||
<link rel="stylesheet" href="/public/themes/{{ config.Theme }}.css">
|
<link rel="stylesheet" href="/public/themes/{{ config.Theme }}.css">
|
||||||
<script src="/public/date.js"></script>
|
<script src="/public/main.js"></script>
|
||||||
<title>Hibiscus.txt</title>
|
<title>Hibiscus.txt</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -32,3 +32,17 @@ function beginTimeUpdater() {
|
||||||
setTimeout(updateTime, difference);
|
setTimeout(updateTime, difference);
|
||||||
updateTime();
|
updateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This does NOT properly sanitize, and assumes a well-meaning user
|
||||||
|
function sanitize(title) {
|
||||||
|
return title
|
||||||
|
.trim()
|
||||||
|
.replace(/ +/g, '-')
|
||||||
|
.replace(/[!*'();:@&=+$,\/?#\[\]]/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a new note
|
||||||
|
function newNote(text_prompt) {
|
||||||
|
name = sanitize(prompt(text_prompt + ':'))
|
||||||
|
window.location.replace('/notes/' + name)
|
||||||
|
}
|
15
routes.go
15
routes.go
|
@ -6,6 +6,7 @@ import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -13,7 +14,7 @@ import (
|
||||||
|
|
||||||
type EntryList struct {
|
type EntryList struct {
|
||||||
Title string
|
Title string
|
||||||
Description string
|
Description template.HTML
|
||||||
Entries []Entry
|
Entries []Entry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ func PostToday(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEntries is a generic HTML renderer for a list
|
// GetEntries is a generic HTML renderer for a list
|
||||||
func GetEntries(w http.ResponseWriter, r *http.Request, title string, description string, dir string, format formatEntries) {
|
func GetEntries(w http.ResponseWriter, r *http.Request, title string, description template.HTML, dir string, format formatEntries) {
|
||||||
filesList, err := ListFiles(dir)
|
filesList, err := ListFiles(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("error reading file list", "directory", dir, "error", err)
|
slog.Error("error reading file list", "directory", dir, "error", err)
|
||||||
|
@ -124,7 +125,11 @@ func GetDays(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// GetNotes renders HTML list of all notes
|
// GetNotes renders HTML list of all notes
|
||||||
func GetNotes(w http.ResponseWriter, r *http.Request) {
|
func GetNotes(w http.ResponseWriter, r *http.Request) {
|
||||||
GetEntries(w, r, TranslatableText("title.notes"), TranslatableText("description.notes"), "notes", func(files []string) []Entry {
|
// This is suboptimal, but will do...
|
||||||
|
description := template.HTML(
|
||||||
|
"<a href=\"#\" onclick='newNote(\"" + TranslatableText("prompt.notes") + "\")'>" + TranslatableText("button.notes") + "</a>" +
|
||||||
|
" <noscript>(" + template.HTMLEscapeString(TranslatableText("noscript.notes")) + ")</noscript>")
|
||||||
|
GetEntries(w, r, TranslatableText("title.notes"), description, "notes", func(files []string) []Entry {
|
||||||
var filesFormatted []Entry
|
var filesFormatted []Entry
|
||||||
for _, v := range files {
|
for _, v := range files {
|
||||||
titleString := strings.Replace(v, "-", " ", -1) // FIXME: what if I need a hyphen?
|
titleString := strings.Replace(v, "-", " ", -1) // FIXME: what if I need a hyphen?
|
||||||
|
@ -195,6 +200,10 @@ func GetNote(w http.ResponseWriter, r *http.Request) {
|
||||||
HandleWrite(w.Write([]byte("note not specified")))
|
HandleWrite(w.Write([]byte("note not specified")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Handle non-latin note names
|
||||||
|
if decodedNote, err := url.QueryUnescape(noteString); err == nil {
|
||||||
|
noteString = decodedNote
|
||||||
|
}
|
||||||
|
|
||||||
GetEntry(w, r, noteString, "notes/"+noteString, true)
|
GetEntry(w, r, noteString, "notes/"+noteString, true)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue