xlog

package module
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 17, 2022 License: MIT Imports: 29 Imported by: 35

README

XLog

Local-first personal knowledge management application with focus on enriching markdown files and surfacing implicit links between pages.

Core Features

  • Uses any directory of markdown files
  • Supports Github flavor markdown (GFM)
  • One statically compiled binary
  • template.md content will be used for new pages
  • Support for nested directories (although not favored)
  • Has a list of tools defined by extensions
  • Add image to the start of a page to make it a cover photo
  • A web server with a very small footprint thanks to Go.
  • Minimal third party dependencies
  • The first Emoji used in the page will be considered the icon of the page and displayed beside the title
  • Shows task list (Done/Total tasks) beside page link (auto links)

Extensions

Extensions are defined under /extensions sub package. each extension is a subpackage. importing the package in cmd/xlog/xlog.go has the side effect of registering the extension hooks. removing the extension from the list of imports will removing the features it provides.

  • autolink: -Shorten a link string so it wouldn't take unnecessary space
  • autolink_pages:
    • Convert a page name mentions in the middle of text to a link
    • List pages that links to the current one in a section at the end of the page.
  • emoji:
    • Emoji autocomplete while editing
  • file_operations
    • Add a tool item to delete current page
    • Add a tool item to rename current page
  • hashtags
    • Support Hashtags #hashtag.
    • Convert any #hashtag to a link to list all pages the uses the hashtag
    • Adds an item in the sidebar to list all hashtags
    • Adds a section after the page to list all pages that used the same hashtags
  • link_preview
    • Preview tweets, Facebook posts, youtube videos, Giphy links
  • opengraph
    • Adds Opengraph meta tags for title, type, image
  • recent
    • Adds an item to sidebar to list all pages ordered by last modified page file.
  • search
    • Full text search
    • Adds a searchbox to the top of the sidebar to search pages and make it easier to create a page from selected text.
  • shortcode
    • adds a way for short codes (one line and block)
    • Defines functions that can be used to add more shortcodes
    • '/' in editor autocompletes from the list of defined shortcodes
  • star
    • Star pages to pin them to sidebar
  • upload_file
    • Drop a file or use the tool to upload the file and include/append it to the current page
    • Record screen/window/tab
    • Screenshot
    • Record Camera + Audio
    • Record Audio only
  • versions
    • Keeps list of pages older versions

Installation

go install github.com/emad-elsaid/xlog/cmd/xlog@latest

Usage

Usage of xlog:
  -bind string
        IP and port to bind the web server to (default "127.0.0.1:3000")
  -build string
        Build all pages as static site in this directory
  -index string
        Index file name used as home page (default "index")
  -readonly
        Should xlog hide write operations, read-only means all write operations will be disabled
  -sidebar
        Should render sidebar. (default true)
  -sitename string
        Site name is the name that appears on the header beside the logo and in the title tag (default "XLOG")
  -source string
        Directory that will act as a storage (default current directory)

Now you can access xlog with localhost:3000

Generating static site

I used Xlog to generate my personal blog. it uses github workflow to do that here is an example.

Overriding Assets

assets is served from assets directory if it exists in the source directory. otherwise the default assets are served from xlog binary. any file under assets that has the same name as the ones xlog uses will be used instead of the default files.

License

Xlog is released under MIT license

Cassette tape icons created by Good Ware - Flaticon

Screenshots

Documentation

Index

Constants

View Source
const (
	STATIC_DIR_PATH  = "public"
	ASSETS_DIR_PATH  = "assets"
	VIEWS_EXTENSION  = ".html"
	CSRF_COOKIE_NAME = "xlog_csrf"
)
View Source
const (
	KB int64 = 1 << (10 * iota)
	MB
	GB
	TB
	PB
)
View Source
const (
	DEBUG = "\033[97;42m"
	INFO  = "\033[97;42m"
)
View Source
const (
	TOOLS_WIDGET widgetSpace = iota
	SIDEBAR_WIDGET
	AFTER_VIEW_WIDGET
	ACTION_WIDGET
	HEAD_WIDGET
)

List of widgets spaces that extensions can use to register a widgetFunc to inject content into.

Variables

View Source
var (
	BIND_ADDRESS string

	CSRF = csrf.TemplateField
)
View Source
var (
	SOURCE   string
	BUILD    string
	READONLY bool
	SITENAME string
	SIDEBAR  bool
	INDEX    string
	TEMPLATE string
)
View Source
var BUILD_PERMS fs.FileMode = 0744

The instance of markdown renderer. this is what takes the page content and converts it to HTML. it defines what features to use from goldmark and what options to turn on

View Source
var PageEvents = PageEventsMap{}

a map to keep all page events and respective list of event handlers

Functions

func AUTOCOMPLETE

func AUTOCOMPLETE(a Autocompleter)

this function registers an autocompleter function. it should be used by an extension to register a new autocompleter function. these functions are going to be executed when rendering the edit page.

func BadRequest

func BadRequest(w http.ResponseWriter, r *http.Request)

func DELETE

func DELETE(path string, handler HandlerFunc, middlewares ...func(http.HandlerFunc) http.HandlerFunc)

func EXTENSION_PAGE

func EXTENSION_PAGE(p string)

func ExtractAllFromAST

func ExtractAllFromAST[t ast.Node](n ast.Node, kind ast.NodeKind) (a []t)

Extract all nodes of a specific type from the AST

func ExtractFirstFromAST

func ExtractFirstFromAST[t ast.Node](n ast.Node, kind ast.NodeKind) (found t, ok bool)

This is a function that takes an AST node and walks the tree depth first recursively calling itself in search for a node of a specific kind can be used to find first image, link, paragraph...etc

func GET

func GET(path string, handler HandlerFunc, middlewares ...func(http.HandlerFunc) http.HandlerFunc)

func HELPER

func HELPER(name string, f interface{})

func IGNORE_DIR

func IGNORE_DIR(r *regexp.Regexp)

Register a pattern to be ignored when walking directories.

func InternalServerError

func InternalServerError(err error) http.HandlerFunc

func Log

func Log(level, label, text string, args ...interface{}) func()

func NoContent

func NoContent(w http.ResponseWriter, r *http.Request)

func NotFound

func NotFound(w http.ResponseWriter, r *http.Request)

func POST

func POST(path string, handler HandlerFunc, middlewares ...func(http.HandlerFunc) http.HandlerFunc)

func PREPEND_WIDGET

func PREPEND_WIDGET(s widgetSpace, f func(*Page, Request) template.HTML)

Register widget function to be rendered in a specific space before any other widget. functions registered by this function will have higher priority than the rest. this function is needed for example to register the search input before any other links in the sidebar

func PREPROCESSOR

func PREPROCESSOR(f PreProcessor)

Register a PREPROCESSOR function. extensions should use this function to register a preprocessor.

func Partial

func Partial(path string, data Locals) string

func PlainText

func PlainText(text string) http.HandlerFunc

func ROUTE

func ROUTE(route http.HandlerFunc, checks ...RouteCheck)

func Redirect

func Redirect(url string) http.HandlerFunc

func Render

func Render(path string, data Locals) http.HandlerFunc

func RenderWidget

func RenderWidget(s widgetSpace, p *Page, r Request) (o template.HTML)

This is used by view and edit routes to render all widgetfuncs registered for specific widget space.

func Start

func Start()

Define the catch all HTTP routes, parse CLI flags and take actions like building the static pages and exit, or start the HTTP server

func Unauthorized

func Unauthorized(w http.ResponseWriter, r *http.Request)

func VIEW added in v0.5.0

func VIEW(view fs.FS)

func Vars added in v0.5.0

func Vars(r Request) map[string]string

func WIDGET

func WIDGET(s widgetSpace, f func(*Page, Request) template.HTML)

Register a function to a widget space. functions registered will be executed in order when rendering view or edit page. the return values of these widgetfuncs will pass down to the template and injected in reserved places.

func WalkPages

func WalkPages(ctx context.Context, f func(*Page))

this function is useful to iterate on all available pages. many extensions uses it to get all pages and maybe parse them and extract needed information

Types

type Autocomplete

type Autocomplete struct {
	StartChar   string
	Suggestions []*Suggestion
}

Autocomplete defines what character triggeres the autocomplete feature and what is the list to display in this case.

type Autocompleter

type Autocompleter func() *Autocomplete

This is a function that returns an auto completer instance. this function should be defined by extensions and registered to be executed when rendering the edit page

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Mux/Handler ===========================================

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w Response, r Request)

type HandlerFunc

type HandlerFunc func(http.ResponseWriter, *http.Request) http.HandlerFunc

type Locals

type Locals map[string]interface{} // passed to views/templates

Some aliases to make it easier

type Output

type Output = http.HandlerFunc

Some aliases to make it easier

func GetPageEditHandler

func GetPageEditHandler(w Response, r Request) Output

Edit page, gets the page from path, if it doesn't exist it'll use the template.md content as default value

func GetPageHandler

func GetPageHandler(w Response, r Request) Output

Shows a page. the page name is the path itself. if the page doesn't exist it redirect to edit page otherwise will render it to HTML

func PostPageHandler

func PostPageHandler(w Response, r Request) Output

Save new content of the page

func RootHandler

func RootHandler(w Response, r Request) Output

Redirect to `/index` to render the index page.

type Page

type Page struct {
	Name string // page name without '.md' extension
	// contains filtered or unexported fields
}

a Type that represent a page.

func NewPage

func NewPage(name string) Page

Create an instance of Page with name. if no name is passed it's assumed "index"

func (*Page) AST

func (p *Page) AST() ast.Node

Parses the page content and returns the Abstract Syntax Tree (AST). extensions can use it to walk the tree and modify it or collect statistics or parts of the page. for example the following "Emoji" function uses it to extract the first emoji.

func (*Page) Content

func (p *Page) Content() string

Reads the underlying file and returns the content

func (*Page) Delete

func (p *Page) Delete() bool

Deletes the file and makes sure it triggers the AfterDelete event

func (*Page) Emoji

func (p *Page) Emoji() string

Returns the first emoji of the page.

func (*Page) Exists

func (p *Page) Exists() bool

checks if the page underlying file exists on disk or not.

func (*Page) FileName

func (p *Page) FileName() string

returns the filename, makes sure it converts slashes to backslashes when needed. this is safe to use when trying to access the file that represent the page

func (*Page) ModTime

func (p *Page) ModTime() time.Time

Return the last modification time of the underlying file

func (*Page) RTL

func (p *Page) RTL() bool

checks if the page includes any arabic character if so it returns true. this is used by the editor to switch direction. it could be useful too for extensions or something

func (*Page) Render

func (p *Page) Render() string

Renders the page content to HTML. it makes sure all preprocessors are called

func (*Page) Write

func (p *Page) Write(content string) bool

Overwrite page content with new content. making sure to trigger before and after write events.

type PageEvent

type PageEvent int

a type used to define events to be used when the page is manipulated for example modified, renamed, deleted...etc.

const (
	BeforeWrite PageEvent = iota
	AfterWrite
	AfterDelete
)

List of page events. extensions can use these events to register a function to be executed when this event is triggered. extensions that require to be notified when the page is created or overwritten or deleted should register an event handler for the interesting events.

type PageEventHandler

type PageEventHandler func(*Page) error

a function that handles a page event. this should be implemented by an extension and then registered. it will get executed when the event is triggered

type PageEventsMap

type PageEventsMap map[PageEvent][]PageEventHandler

a map of all handlers functions registered for each page event.

func (PageEventsMap) Listen

func (c PageEventsMap) Listen(e PageEvent, h PageEventHandler)

Register an event handler to be executed when PageEvent is triggered. extensions can use this to register hooks under specific page events. extensions that keeps a cached version of the pages list for example needs to register handlers to update its cache

func (PageEventsMap) Trigger

func (c PageEventsMap) Trigger(e PageEvent, p *Page)

Trigger event handlers for a specific page event. page methods use this function to trigger all registered handlers when the page is edited or deleted for example.

type PreProcessor

type PreProcessor func(string) string

A PreProcessor is a function that takes the whole page content and returns a modified version of the content. extensions should define this type and register is so that when page is rendered it will execute all of them in order like a pipeline each function output is passed as an input to the next. at the end the last preprocessor output is then rendered to HTML

type Request

type Request = *http.Request

Some aliases to make it easier

type Response

type Response = http.ResponseWriter

Some aliases to make it easier

type Route

type Route struct {
	// contains filtered or unexported fields
}

Mux/Handler ===========================================

type RouteCheck

type RouteCheck func(Request) (Request, bool)

Mux/Handler ===========================================

type Suggestion

type Suggestion struct {
	Text        string // The text that gets injected in the editor if this option is choosen
	DisplayText string // The display text for this item in the menu. this can be more cosmetic.
}

Suggestions represent an item in the list of autocomplete menu in the edit page

Directories

Path Synopsis
cmd
assets
This script is used to compile assets to local directory
This script is used to compile assets to local directory
extensions

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL