diff --git a/README.md b/README.md index 5653d67..4bdcbee 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,11 @@ Clone this repository and run `go build` to build `nirvash`. Just running `./nir ``` adapter=eureka // one of the supported adapters, currently just eureka root=/path/to/ssg/root // path to where your SSG content root is -assetRoot=/path/to/asset/root // path to the Nirvash static assets (eg static/ directory in this repo) +assetRoot=/path/to/asset/root // path to the parent folder containing Nirvash static/ assets and templates/ directory (eg base directory of this repo) staticRoot=/path/to/static/root // path to static file storage on your webserver +staticShowHTML=false // true or false, show HTML files in the file manager interface +staticShowHidden=false // true or false, show hidden files in the file manager interface +staticMaxUploadMB=25 // integer, maximum size in MB of files uploaded in the file manager interface plugins=none // list of plugins to use, currently none are implemented ``` @@ -30,4 +33,31 @@ User management is done from the command line as well: Running `nirvash` without any arguments starts the webserver on port 8080. -MORE TO COME \ No newline at end of file +Initially the user will be presented with the login screen; upon successful login, the application presents the navbar with these options: + +- `Pages`: the default page, shows a list of existing pages - clicking one enables editing that page; a button is also presented for adding a new page. Each `Adapter` will provide different formatting help and can allow editable slugs/URLs or not (eg, the `EurekaAdapter` builds slugs/URLs directly from the page title). +- `Files`: provides an interface for managing statically hosted files. Files and directories can be added, moved, and deleted. +- `Build`: a simple form to build the site - build options configurable by `Adapter` are present under an accordion. +- `Configuration`: interface to the configuration for the `Adapter`. Each `Adapter` provides its own configuration interface with associated data types (currently supported: `int`, `float`, `string`, and `multilinestring`) +- `Logout`: logs the user out and returns to the login screen + +## adapter interface + +`nirvash` is extensible by `Adapter`s that can interact with almost any static site generator under the hood. + +The `Adapter` interface and associated data types can be found in the [adapter.go](https://nilfm.cc/git/nirvash/tree/archetype/adapter.go) file, but the basic interface looks like this: + +- `Init(cfg *Config)`: set any initial settings that need to be handled - typically import SSG data root from the `nirvash` config file and read the SSG's own config file +- `Name() string`: the name of the adapter, used for the `nirvash.conf` config file +- `EditableSlugs() bool`: whether slugs can be edited independently or are calculated based on, eg, page titles +- `BuildOptions() []string`: a list of names of the build options to present on the `/build` page +- `GetConfig() map[ConfigOption]string`: retrieves the config to present on the `/config` page +- `SetConfig(map[ConfigOption]string) error`: takes the config from the `/config` page and applies it, typically by writing it to a file +- `ListPages() map[string]string`: list the pages in the site; keys are the slugs, values are the titles +- `GetPage(slug string) Page`: given a slug, return the page data +- `FormatPage(string) string`: given the raw page data as input by the user, return HTML suitable for preview (currently unimplemented and unused) +- `FormattingHelp() string`: return a string to be inserted into a `pre` tag on the `/fmt-help` page +- `CreatePage(slug, title, content string) error`: given all the proper arguments, create a new page in the backing store (eg filesystem, db) +- `SavePage(oldSlug, newSlug, title, content string) error`: given all the proper arguments, save a page to the backing store (eg filesystem, db) +- `DeletePage(slug string) error`: given a slug, delete the corresponding page source and possibly its generated HTML, depending on the `Adapter` +- `Build(buildOptions map[string][]string) BuildStatus`: takes a map of build option names to their values and builds the site, returning a `BuildStatus` object containing the success or failure as a boolean and the detailed status (eg, the console ouptut of the build process) \ No newline at end of file diff --git a/archetype/adapter.go b/archetype/adapter.go index 4fecc96..c9aff16 100644 --- a/archetype/adapter.go +++ b/archetype/adapter.go @@ -29,8 +29,8 @@ type Adapter interface { GetConfig() map[ConfigOption]string SetConfig(map[ConfigOption]string) error ListPages() map[string]string - GetPage(string) Page - FormatPage(string) string + GetPage(slug string) Page + FormatPage(raw string) string FormattingHelp() string CreatePage(slug, title, content string) error SavePage(oldSlug, newSlug, title, content string) error diff --git a/archetype/config.go b/archetype/config.go index ea13c82..aeb5b42 100644 --- a/archetype/config.go +++ b/archetype/config.go @@ -5,17 +5,19 @@ import ( "os" "path/filepath" "runtime" + "strconv" "strings" ) type Config struct { - Adapter Adapter // adapter for this instance - Root string // root of the site data - StaticRoot string // root of static files for StaticFileManager - StaticShowHidden bool // whether to show hidden files in the StaticFileManager - StaticShowHtml bool // whether to show html files in the StaticFileManager - AssetRoot string // root of Nirvash dist files (CSS, images) - Plugins map[string]interface{} + Adapter Adapter // adapter for this instance + Root string // root of the site data + StaticRoot string // root of static files for StaticFileManager + StaticShowHidden bool // whether to show hidden files in the FileManager + StaticShowHTML bool // whether to show html files in the FileManager + StaticMaxUploadMB int64 // max size in MB of files uploaded via FileManager + AssetRoot string // root of Nirvash dist files (CSS, images) + Plugins map[string]interface{} } func GetConfigLocation() string { @@ -63,6 +65,7 @@ func (self *Config) SetAdapter(adapter string) { } func (self *Config) IsNull() bool { + // zero-values for StaticShowHTML, StaticShowHidden, and StaticMaxUploadMB are valid return self.Adapter == nil || len(self.Root) == 0 || len(self.StaticRoot) == 0 || len(self.AssetRoot) == 0 } @@ -88,11 +91,22 @@ func (self *Config) RunWizard() { self.Root = inputBuf inputBuf = "" - fmt.Printf("static file root? ") ensureNonEmptyOption(&inputBuf) self.StaticRoot = inputBuf + inputBuf = "" + fmt.Printf("show HTML files in file manager? ") + self.StaticShowHTML = ensureBooleanOption(&inputBuf) + + inputBuf = "" + fmt.Printf("show hidden files in file manager? ") + self.StaticShowHidden = ensureBooleanOption(&inputBuf) + + inputBuf = "" + fmt.Printf("max upload size (MB)? ") + self.StaticMaxUploadMB = ensureNumberOption(&inputBuf) + inputBuf = "" fmt.Printf("nirvash asset root? ") ensureNonEmptyOption(&inputBuf) @@ -113,6 +127,31 @@ func ensureNonEmptyOption(buffer *string) { if len(strings.TrimSpace(*buffer)) != 0 { break } + fmt.Println("Please enter a nonempty value") + } +} + +func ensureBooleanOption(buffer *string) bool { + for { + fmt.Scanln(buffer) + trimmedBuf := strings.TrimSpace(*buffer) + v, err := strconv.ParseBool(trimmedBuf) + if err == nil { + return v + } + fmt.Println("Please enter a true or false value") + } +} + +func ensureNumberOption(buffer *string) int64 { + for { + fmt.Scanln(buffer) + trimmedBuf := strings.TrimSpace(*buffer) + v, err := strconv.ParseInt(trimmedBuf, 10, 64) + if err == nil && v > 0 { + return v + } + fmt.Println("Please enter a positive integer") } } @@ -126,6 +165,9 @@ func writeConfig(cfg *Config, configFile string) error { f.WriteString("root=" + cfg.Root + "\n") f.WriteString("staticRoot=" + cfg.StaticRoot + "\n") + f.WriteString("staticShowHTML=" + strconv.FormatBool(cfg.StaticShowHTML) + "\n") + f.WriteString("staticShowHidden=" + strconv.FormatBool(cfg.StaticShowHidden) + "\n") + f.WriteString("staticMaxUploadMB=" + strconv.FormatInt(cfg.StaticMaxUploadMB, 10) + "\n") f.WriteString("assetRoot=" + cfg.AssetRoot + "\n") f.WriteString("adapter=" + cfg.Adapter.Name() + "\n") f.WriteString("plugins=\n") @@ -159,6 +201,12 @@ func parseConfig(configFile string) *Config { cfg.Root = v case "staticRoot": cfg.StaticRoot = v + case "staticShowHTML": + cfg.StaticShowHTML, _ = strconv.ParseBool(v) + case "staticShowHidden": + cfg.StaticShowHidden, _ = strconv.ParseBool(v) + case "staticMaxUploadMB": + cfg.StaticMaxUploadMB, _ = strconv.ParseInt(v, 10, 64) case "assetRoot": cfg.AssetRoot = v case "plugins": diff --git a/archetype/eureka.go b/archetype/eureka.go index 16c9151..583da5b 100644 --- a/archetype/eureka.go +++ b/archetype/eureka.go @@ -112,7 +112,70 @@ func (self *EurekaAdapter) FormatPage(raw string) string { func (self *EurekaAdapter) FormattingHelp() string { // TODO: show Eureka formatting guide - return "help!" + return `// shorthand for linking other pages +{page name} + +// shorthand for page transclusion +{/page name} + +// shorthand for arbitary link +{*destination url|text} + +// shorthand for an image you can click to see the full sized version +{:anchor-id|image url|alt text} + +// shorthand for an image with arbitrary link destination +{?anchor-id|destination url|image url|alt text} + +// shorthand for an audio player +{_/path/to/media} + +// shorthand for paragraphs, can embed other markup inside it +{¶graph text {with a link} {@and some bold text}} + +// shorthand for ordered lists, can embed other markup inside it +{# + {-item one} + {-item two} + {-item three} +} + +// shorthand for unordered lists, can embed other markup inside it +{, + {-item one} + {-item two} + {-item three} +} + +// shorthand for bold +{@bold text} + +// shorthand for italic +{~italic text} + +// shorthand for code +{` + "`" + `short code} + +// shorthand for pre +{$longer code} + +// shorthand for quote +{'short quote} + +// shorthand for blockquote +{>longer quote} + +// shorthand for strikethrough +{\crossed-out text} + +// shorthand for level 3 heading +{!heading text} + +// shorthand for level 4 heading +{.heading text} + +// shorthand for publish date (renders as