storytempl

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Apr 1, 2024 License: MIT Imports: 19 Imported by: 0

README

storytempl

About

This package runs a Storybook server for Templ components so that you can preview them during development. This is possible because the Storybook server renderer supports components that are rendered on a web server.

We take advantage of this by wrapping our components in HTTP handlers. Storybook provides parameters in the query string of the request and this package passes them into your component function.

You must have "pnpm" or "npm" on your system so that the appropriate Storybook packages can be installed when the server runs.

All of the Storybook arg types are supported.

Example Usage

Here we have a simple Templ component that can show a button in a few different styles.

// button.templ
package main

templ StyledButton(label string, className string) {
  <style>
    button.primary {
        background-color: #007bff;
        color: white;
    }

    button.secondary {
        background-color: #6c757d;
        color: white;
    }

    button.danger {
        background-color: #dc3545;
        color: white;
    }
  </style>

  <div class="box">
    <button class={ className }>{label}</button>
  </div>
}

Next we create a function that sets up the argument types, default values, and stories for this component.

// button_stories.go
package main

import "gitlab.com/joeslazaro/storytempl"

func StyledButtonStories() *storytempl.Conf {
  return storytempl.NewConf("Example/Button").
    AddArgTypes(
      storytempl.TextArgType("label"),
      storytempl.SelectArgType("className", []string{"primary", "secondary", "danger"}),
    ).
    AddDefaultArgs(
      storytempl.TextArg("label", "Click Me"),
      storytempl.SelectArg("className", "primary"),
    ).
    AddStory("Default"). // No story-specific args set
    AddStory("Secondary",
      // we'll override the default className
      storytempl.SelectArg("className", "secondary"),
    ).
    AddStory("Danger",
      // we'll override both default arg values
      storytempl.SelectArg("label", "Danger button"),
      storytempl.SelectArg("className", "danger"),
    )
}

Then we create a storybook config, add our components + stories, and start the server.

// main.go
package main

import "gitlab.com/joeslazaro/storytempl"

func main() {
  sbook := storytempl.New().AddComponent(StyledButton, StyledButtonStories())
  if err := sbook.ListenAndServe(); err != nil {
    panic(err)
  }
}

Here is what it looks like when we connect to the server on localhost:60606. Screenshot of storybook

Further examples

As mentioned before, all of the Storybook arg types are supported, and you can look at the _examples subdirectory to see an example of each one. You can also look at args.go, which is where they are defined.

You can also clone this repository and run task example to run a server with all of the examples, assuming that you have the Taskfile and Templ executables in your path.

Organizing your story files

In my example I could have created the StyledButtonStories() in the same file as the templ component, however then I would have lost out on the assistance I get in VSCode from the Go language server. That's why, in my examples, I've chosen to have separate *_stories.go files for each of the examples.

If you're using VSCode, I recommend that you configure file nesting for "*.templ" files so that you can fold related files under it. I'm using $(capture)_templ.go, $(capture)_templ.txt, $(capture)_stories.go

Hot reloading?

I spent about five minutes testing this with templ's --watch and --proxy flags, but I wasn't able to get Storybook to see the changes. If anyone happens to figure it out, please let me know :)

History

The initial code was based on a more basic Storybook wrapper that I found in the Templ repository. I wanted to expand upon this work to supporting the full capabilities of Storybook argument types and allowing multiple stories per component

Documentation

Overview

Package storytempl runs a Storybook server for Templ components so that you can preview them during development.

Index

Constants

View Source
const NPM_CMD = "npm"
View Source
const PNPM_CMD = "pnpm"

Variables

This section is empty.

Functions

func NewHandler

func NewHandler(name string, templateFn interface{}, conf *Conf) http.Handler

NewHandler wraps a templ.Component with a handler that automatically extracts any query parameters from the request and passes them into the component.

Types

type Arg

type Arg struct {
	Name  string
	Value interface{}
}

func BooleanArg

func BooleanArg(name string, value bool) Arg

Provides a true/false toggle.

func CheckArg

func CheckArg(name string, value string) Arg

Value for a check/inline-check arg.

func ColorArg

func ColorArg(name, value string) Arg

Value for a color arg.

func DateArg

func DateArg(name string, value time.Time) Arg

Value for a date arg.

func FileArg

func FileArg(name, value string) Arg

Value for a file arg.

func FloatArg

func FloatArg(name string, value float64) Arg

Value for a float arg.

func NumberArg

func NumberArg(name string, value int) Arg

Value for a number arg.

func ObjectArg

func ObjectArg(name string, value interface{}) Arg

Value for an object arg.

func RadioArg

func RadioArg(name string, value string) Arg

Value for a radio/inline-radio arg.

func RangeArg

func RangeArg(name string, value int) Arg

Value for a number arg.

func SelectArg

func SelectArg(argName string, option string) Arg

Value for a select/multi-select arg.

func TextArg

func TextArg(name, value string) Arg

Value for a text arg.

type ArgType

type ArgType struct {
	Name    string
	Control interface{}
	Options *[]string
	// Function to retrieve/decode the value from a URL query string
	Get queryParamGetter
	// Optional arg value validator for this arg type
	Validate func(interface{}) error
}

func BooleanArgType

func BooleanArgType(name string) ArgType

Provides a toggle for switching between possible states.

func CheckArgType

func CheckArgType(name string, options []string) ArgType

Provides a set of stacked checkboxes for selecting multiple options.

func CheckInlineArgType

func CheckInlineArgType(name string, options []string) ArgType

Provides a set of inlined checkboxes for selecting multiple options.

func ColorArgType

func ColorArgType(name string, presetColors *[]string) ArgType

Provides a color picker to choose color values. Can be optionally configured to include a set of color presets that show in the color picker.

func DateArgType

func DateArgType(name string) ArgType

Provides a datepicker to choose a date which is returned as a time.Time type.

func FileArgType

func FileArgType(name, accept string) ArgType

Provides a file input that returns an array of URLs formatted as a string. Can be further customized to accept specific file types.

func FloatArgType

func FloatArgType(name string, min, max, step float64) ArgType

Provides a float64 numeric input with optional min/max/step.

func NumberArgType

func NumberArgType(name string, conf *NumberArgConf) ArgType

Provides a numeric input with optional min/max/step.

func ObjectArgType

func ObjectArgType(name string, valuePtr interface{}) ArgType

func RadioArgType

func RadioArgType(name string, options []string) ArgType

Provides a set of stacked radio buttons based on the available options.

func RadioInlineArgType

func RadioInlineArgType(name string, options []string) ArgType

Provides a set of inlined radio buttons based on the available options.

func RangeArgType

func RangeArgType(name string, conf *NumberArgConf) ArgType

Provides a numeric range slider with optional min/max/step.

func SelectArgType

func SelectArgType(name string, options []string) ArgType

Provides a select to choose a single value from the options.

func SelectMultiArgType

func SelectMultiArgType(name string, options []string) ArgType

Provides a select to choose any number of the provided options.

func TextArgMaxLenType

func TextArgMaxLenType(name string, maxLen int) ArgType

Provides a text input with a maximum length.

func TextArgType

func TextArgType(name string) ArgType

Provides a text input.

type Conf

type Conf struct {
	Title      string                                `json:"title"`
	Parameters storyParameters                       `json:"parameters"`
	Args       *util.OrderedMap[string, interface{}] `json:"args"`
	ArgTypes   *util.OrderedMap[string, interface{}] `json:"argTypes"`
	Stories    []story                               `json:"stories"`
	// contains filtered or unexported fields
}

This is the "real" config that will get turned into a *_stories.json file.

func NewConf

func NewConf(title string) *Conf

func (*Conf) AddArgTypes

func (cb *Conf) AddArgTypes(argTypes ...ArgType) *Conf

func (*Conf) AddDefaultArgs

func (cb *Conf) AddDefaultArgs(args ...Arg) *Conf

func (*Conf) AddStory

func (cb *Conf) AddStory(name string, args ...Arg) *Conf

func (*Conf) SlugTitle added in v0.2.0

func (cb *Conf) SlugTitle() string

func (*Conf) Validate added in v0.2.0

func (conf *Conf) Validate() error

type NumberArgConf

type NumberArgConf struct{ Min, Max, Step *int }

func NewNumberArgConf

func NewNumberArgConf() *NumberArgConf

func (*NumberArgConf) SetMax

func (conf *NumberArgConf) SetMax(max int) *NumberArgConf

func (*NumberArgConf) SetMin

func (conf *NumberArgConf) SetMin(min int) *NumberArgConf

func (*NumberArgConf) SetStep

func (conf *NumberArgConf) SetStep(step int) *NumberArgConf

type Storybook

type Storybook struct {
	// Path to the directory where storybook files will be installed.
	// Defaults to "storybook-server".
	ServerPath string
	// Host and port number to bind to, such as "localhost:8080" or ":60606" (default)
	ServerAddress string
	// Header to be included in the <head> of the storybook preview.
	Header string
	// A name of the npm executable to use, either 'pnpm' or 'npm'.
	// Defaults to trying both in that order if not set.
	NpmExecutable string
	// Main configuration to be copied to .storybook/main.js.
	MainJS string
	// Javascript code to be copied to .storybook/preview.js.
	PreviewJS string
	// Component configuration used to generate the stories.
	Config map[string]*Conf
	// http Handlers to wrap each of the component templates.
	Handlers map[string]http.Handler
	// Handler used to serve files generated by `storybook build`
	StaticHandler http.Handler
	// Optional path to directory which will be available with a /static path
	// prefix. Useful for serving JS/CSS referenced by Header.
	UserStaticFilesDir string
	// Skip the Storybook install/build step if true, and only serve the
	// components. Meant to be used for testing.
	SkipBuild bool
	Log       *slog.Logger
	Server    http.Server
	// contains filtered or unexported fields
}

func New

func New() *Storybook

func (*Storybook) AddComponent

func (sb *Storybook) AddComponent(componentConstructor interface{}, conf *Conf) *Storybook

Adds a component to Storybook. The title can have a slash to create a hierarchy of components in the Storybook UI.

func (*Storybook) GetComponentPath added in v0.2.0

func (sb *Storybook) GetComponentPath(conf *Conf) string

func (*Storybook) GetComponentURL added in v0.2.0

func (sb *Storybook) GetComponentURL(title string) string

func (*Storybook) GetPreviewHandler added in v0.2.0

func (sb *Storybook) GetPreviewHandler() http.Handler

Returns the http.Handler that serves the rendered templates with a "/preview/" prefix in case you want to use it with your own server. Used for unit testing.

func (*Storybook) ListenAndServe

func (sb *Storybook) ListenAndServe() error

Starts the Storybook web UI. ListenAndServe wraps ListenAndServeWithContext using context.Background.

func (*Storybook) ListenAndServeWithContext

func (sb *Storybook) ListenAndServeWithContext(ctx context.Context) error

Starts the Storybook web UI with context.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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