margo

package module
v0.0.0-...-b74dff7 Latest Latest
Warning

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

Go to latest
Published: Jan 24, 2025 License: MIT Imports: 25 Imported by: 0

README

Margo CMS

Margo is a Markdown-driven Content Management System (CMS) built with Go, TailwindCSS, and Templ. It leverages file-based routing and provides developers with a robust, scalable, and intuitive framework for building high-performance websites. Margo is a part of the larger IOTA SDK ecosystem, a modular ERP solution designed for diverse industries like finance, manufacturing, and warehouse management.

Key Features

  • Markdown-Driven Content: Create and manage content in Markdown files, enabling a simple and effective way to write and update content.
  • File-Based Routing: Automatically maps files to routes, making navigation structure intuitive and developer-friendly.
  • Go-Powered: Benefit from the performance, concurrency, and security of the Go programming language.
  • TailwindCSS Integration: Use TailwindCSS to style your projects with ease, ensuring a modern and consistent design system.
  • Templ Components: Use Templ for fast, modular, and reusable UI components.

Prerequisites

Before you begin, ensure you have the following installed:

  • Go (v1.20 or later)
  • Node.js (for TailwindCSS and related tooling)
  • templ (install via go install github.com/a-h/templ/cmd/templ@latest)
  • Margo: Install Margo via:
go get github.com/iota-uz/margo

Getting Started

1. Initialize the Project

Create a new Go project and import Margo:

mkdir my-margo-project
cd my-margo-project
go mod init github.com/your-username/my-margo-project

Install dependencies:

go get github.com/iota-uz/margo
npm install
2. Register Components

Margo components are provided via layouts and registry. Example setup:

package ui

import (
	"github.com/iota-uz/margo/registry"

	"github.com/username/your-project/components/button"
	"github.com/username/your-project/components/primitives"
	"github.com/username/your-project/components/typography"
)

func BlogLayout() registry.Layout {
	layout := registry.NewLayout("Blog")

	// typography
	layout.Register("h1", typography.H1)
	layout.Register("h2", typography.H2)
	layout.Register("h3", typography.H3)
	layout.Register("h4", typography.H4)
	layout.Register("h5", typography.H5)
	layout.Register("h6", typography.H6)

	// primitives
	layout.Register("a", primitives.Link)
	layout.Register("ul", primitives.List)
	layout.Register("li", primitives.Item)
	layout.Register("img", primitives.Image)

	// buttons
	layout.Register("ButtonPrimary", button.Primary)
	layout.Register("ButtonSecondary", button.Secondary)
	layout.Register("ButtonDanger", button.Danger)

	return layout
}

func Registry() registry.Registry {
	r := registry.New()
	r.RegisterLayout(BlogLayout())
	return r
}
3. Run the Development Server

Generate Templ files:

templ generate

Start the Go server:

go run .

Run Tailwind in development mode:

npx tailwindcss -i ./assets/styles.css -o ./public/styles.css --watch

Open your browser and navigate to http://localhost:8080.

Project Structure

my-margo-project/
├── assets/         # TailwindCSS input files
├── components/     # Reusable Templ components
├── content/        # Markdown files for pages
├── layouts/        # Layout templates
├── public/         # Generated CSS and static assets
├── routes/         # File-based routing logic
├── main.go         # Application entry point
└── tailwind.config.js # TailwindCSS configuration

Creating Content

Add Markdown files in the content/ directory. File names map directly to routes. For example:

  • content/index.md -> /
  • content/about.md -> /about
Frontmatter

Use YAML frontmatter for metadata:

---
title: "About Us"
description: "Learn more about our mission and values."
---

Welcome to our website!

File-Based Routing

Routes are automatically generated based on the directory structure in content/. Customize routing logic in the routes/ package if needed.

Extending Margo

Adding Components

Create reusable Templ components in the components/ directory. For example:

package components

import (
	"github.com/iota-uz/margo/registry"
	"github.com/a-h/templ"
)

func ButtonPrimary(props struct {
	Text string
	Href string
}) templ.Component {
	return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
		_, err := w.Write([]byte(`<a href="` + props.Href + `" class="btn-primary">` + props.Text + `</a>`))
		return err
	})
}

func Register(layout registry.Layout) {
	layout.Register("ButtonPrimary", ButtonPrimary)
}

Use the component in your templates:

@components.ButtonPrimary({
	Text: "Learn More",
	Href: "/about",
})
Styling with TailwindCSS

Define your styles in assets/styles.css and extend Tailwind in tailwind.config.js as needed.

Custom Logic

Add custom middleware, handlers, or utilities in main.go or the routes/ package.

Deployment

  1. Build the Go application:
go build -o margo
  1. Compile TailwindCSS for production:
npx tailwindcss -i ./assets/styles.css -o ./public/styles.css --minify
  1. Deploy the margo binary and the public/ directory to your server or hosting provider.

Testing

Run Unit Tests

Use the Go testing framework:

go test ./...
Linting and Formatting

Format your Go code:

go fmt ./...

Lint your code:

golangci-lint run

Community and Support

License

Margo is licensed under the MIT License.


Happy coding with Margo!

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Extension

func Extension(layout registry.Layout) goldmark.Extender

func GetLayout

func GetLayout(ctx context.Context) (string, bool)

GetLayout retrieves a layout from context

func GetSlot

func GetSlot(ctx context.Context) (templ.Component, bool)

GetSlot retrieves a component from context

func WithLayout

func WithLayout(ctx context.Context, layout string) context.Context

WithLayout adds a layout to context

func WithSlot

func WithSlot(ctx context.Context, component templ.Component) context.Context

WithSlot adds a component to context

Types

type ComponentBuilder

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

func NewComponentBuilder

func NewComponentBuilder(reg registry.Layout) *ComponentBuilder

func (*ComponentBuilder) Build

func (cb *ComponentBuilder) Build(component any, attrs []ast.Attribute) (templ.Component, error)

func (*ComponentBuilder) GetComponent

func (cb *ComponentBuilder) GetComponent(name string, ns registry.Layout) (any, error)

type ContextKey

type ContextKey struct{}

ContextKey is used for context value storage

type Markdown

type Markdown interface {
	goldmark.Markdown
	ConvertToTempl(source []byte, opts ...parser.ParseOption) templ.Component
}

func New

func New(reg registry.Layout) Markdown

New returns a new Markdown with given options.

type MarkdownRenderer

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

MarkdownRenderer implements custom markdown rendering

func (*MarkdownRenderer) AddOptions

func (r *MarkdownRenderer) AddOptions(opts ...renderer.Option)

func (*MarkdownRenderer) Register

func (r *MarkdownRenderer) Register(kind ast.NodeKind, v renderer.NodeRendererFunc)

func (*MarkdownRenderer) RegisterFuncs

func (r *MarkdownRenderer) RegisterFuncs(registerer renderer.NodeRendererFuncRegisterer)

func (*MarkdownRenderer) Render

func (r *MarkdownRenderer) Render(w io.Writer, source []byte, n ast.Node) error

func (*MarkdownRenderer) RenderToTempl

func (r *MarkdownRenderer) RenderToTempl(source []byte, n ast.Node) templ.Component

type NodeRenderer

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

NodeRenderer handles different types of markdown nodes

func NewNodeRenderer

func NewNodeRenderer(
	builder *ComponentBuilder,
	layout registry.Layout,
	parent *MarkdownRenderer,
) *NodeRenderer

func (*NodeRenderer) RenderNode

func (nr *NodeRenderer) RenderNode(ctx context.Context, w io.Writer, source []byte, node ast.Node) error

RenderNode is the main entry point for rendering nodes

type Renderer

type Renderer interface {
	renderer.Renderer
	RenderToTempl(source []byte, n ast.Node) templ.Component
}

func NewRenderer

func NewRenderer(reg registry.Layout, options ...renderer.Option) Renderer

NewRenderer creates a new markdown renderer

type ValueSetter

type ValueSetter struct{}

func NewValueSetter

func NewValueSetter() *ValueSetter

func (*ValueSetter) SetTypedValue

func (vs *ValueSetter) SetTypedValue(field reflect.Value, value interface{}) error

Directories

Path Synopsis
templ: version: v0.3.819
templ: version: v0.3.819

Jump to

Keyboard shortcuts

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