theme

package
v0.0.7 Latest Latest
Warning

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

Go to latest
Published: Aug 1, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Overview

Package theme 提供主题管理功能:解析 theme.yaml、管理主题生命周期。

Index

Constants

View Source
const (
	// WidgetSourceBuiltin 表示内置组件。
	WidgetSourceBuiltin = "builtin"
	// WidgetSourceTheme 表示主题提供的组件。
	WidgetSourceTheme = "theme"
	// WidgetSourcePlugin 表示插件提供的组件。
	WidgetSourcePlugin = "plugin"
)
View Source
const MenuItemTypeCustom = "custom"
View Source
const MenuItemTypePage = "page"

Variables

View Source
var BuiltinWidgetDecls = []WidgetDecl{
	{ID: "user_info", Label: gettext.Mark.T("用户信息"), Options: []OptionDecl{
		{ID: "title", Type: "text", Label: gettext.Mark.T("标题"), Description: gettext.Mark.T("留空时根据登录状态显示欢迎语")},
	}},
	{ID: "search", Label: gettext.Mark.T("搜索"), Options: []OptionDecl{
		{ID: "title", Type: "text", Label: gettext.Mark.T("标题"), Default: gettext.Mark.T("搜索")},
	}},
	{ID: "recent_posts", Label: gettext.Mark.T("近期文章"), Options: []OptionDecl{
		{ID: "title", Type: "text", Label: gettext.Mark.T("标题"), Default: gettext.Mark.T("近期文章")},
		{ID: "count", Type: "number", Label: gettext.Mark.T("显示数量"), Default: "5", Min: floatPtr(1), Max: floatPtr(20)},
	}},
	{ID: "recent_comments", Label: gettext.Mark.T("近期评论"), Options: []OptionDecl{
		{ID: "title", Type: "text", Label: gettext.Mark.T("标题"), Default: gettext.Mark.T("近期评论")},
		{ID: "count", Type: "number", Label: gettext.Mark.T("显示数量"), Default: "5", Min: floatPtr(1), Max: floatPtr(20)},
	}},
	{ID: "categories", Label: gettext.Mark.T("分类目录"), Options: []OptionDecl{
		{ID: "title", Type: "text", Label: gettext.Mark.T("标题"), Default: gettext.Mark.T("分类目录")},
	}},
	{ID: "tag_cloud", Label: gettext.Mark.T("标签云"), Options: []OptionDecl{
		{ID: "title", Type: "text", Label: gettext.Mark.T("标题"), Default: gettext.Mark.T("标签")},
	}},
	{ID: "archive_months", Label: gettext.Mark.T("归档"), Options: []OptionDecl{
		{ID: "title", Type: "text", Label: gettext.Mark.T("标题"), Default: gettext.Mark.T("归档")},
	}},
	{ID: "custom_html", Label: gettext.Mark.T("自定义 HTML"), Options: []OptionDecl{
		{ID: "title", Type: "text", Label: gettext.Mark.T("标题")},
		{ID: "html", Type: "textarea", Label: gettext.Mark.T("HTML 内容"), Description: gettext.Mark.T("任意 HTML 代码,会原样输出到页面中")},
	}},
}

BuiltinWidgetDecls 内置组件声明。主题只需要声明组件区域即可使用这些组件; 若主题在 theme.yaml 中声明了同 ID 组件,则以主题声明为准。

View Source
var BuiltinWidgetIDs = []string{"user_info", "search", "recent_posts", "recent_comments", "categories", "tag_cloud", "archive_months", "custom_html"}

BuiltinWidgetIDs 内置组件 ID 列表。

Functions

func HasLegacyWidgetConfig

func HasLegacyWidgetConfig(userConfigJSON string) bool

HasLegacyWidgetConfig 判断配置中是否存在缺少 source 的旧格式条目。 插件化后组件 ID 不再全局唯一,旧格式无法可靠判断来源,因此需要清空后重新配置。

func IsBuiltinWidget

func IsBuiltinWidget(id string) bool

IsBuiltinWidget 判断是否为内置组件。

func MarshalMenuConfig

func MarshalMenuConfig(items []MenuConfigItem) (string, error)
func MenuPageID(id uint) string
func MenuSettingKey(location string) string

func MissingWidgets

func MissingWidgets(userConfigJSON string, t *Theme) []string

MissingWidgets 返回用户配置中存在但当前主题未声明的组件 ID 列表。

func OptionKey

func OptionKey(themeName, optionID string) string

OptionKey 返回 option 在 Setting 表中的 key。 格式:option_<theme_name>_<option_id>

func RegisterBuiltins

func RegisterBuiltins(r *hook.WidgetRegistry)

RegisterBuiltins 注册所有内置组件到注册表。

func RegisterThemeWidgets

func RegisterThemeWidgets(widgetRegistry *hook.WidgetRegistry, t *Theme)

RegisterThemeWidgets 注册主题声明的组件到注册表。

Types

type API

type API struct {
	*hook.API
	// contains filtered or unexported fields
}

API 是 hook.API 在 internal/theme 中的包装,负责桥接内部主题声明类型。

func NewAPI

func NewAPI(domain string, loader *store.DataLoader, opts []OptionDecl) *API

NewAPI 创建主题 Hook API 实例。

func (*API) SetHookRegistry

func (api *API) SetHookRegistry(hooks hook.Registry, source hook.Source)

SetHookRegistry 设置当前主题注册 action/filter 使用的 Hook Registry。

type FunctionsScript

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

FunctionsScript 表示一个已编译的 functions.go 脚本。

func CompileFunctions

func CompileFunctions(ctx context.Context, themeDir string, api *API, log *slog.Logger) (*FunctionsScript, error)

CompileFunctions 编译主题目录下的 functions.go 或 functions.goyaegi 文件。 返回编译后的脚本实例;如果文件不存在则返回 nil, nil。

type Manager

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

Manager 管理主题的安装、激活、删除。

func NewManager

func NewManager(themesDir string, store hook.SettingStore, renderer *render.Renderer) (*Manager, error)

NewManager 创建主题管理器。themesDir 是主题存放目录(如 "themes")。

func (*Manager) Activate

func (m *Manager) Activate(ctx context.Context, name string) error

Activate 激活指定主题并持久化。

func (*Manager) BindTemplateFunctions

func (m *Manager) BindTemplateFunctions()

BindTemplateFunctions 把主题运行时能力绑定到模板函数。

主题模板中的函数调用统一走这条链路:

模板函数 → render.RequestContext → theme.Manager → store/主题声明。

这样 cmd/server 只负责组装依赖,不再了解 widget/option 的 Setting key 细节。

func (*Manager) ClearPreviewTheme

func (m *Manager) ClearPreviewTheme()

ClearPreviewTheme 清除 Renderer 中的预览主题模板缓存。

func (*Manager) ClearRecoveryInfo

func (m *Manager) ClearRecoveryInfo()

ClearRecoveryInfo 清除恢复信息(管理员确认后调用)。

func (*Manager) Current

func (m *Manager) Current(ctx context.Context) *Theme

Current 返回当前激活的主题名称。

func (*Manager) CurrentScript

func (m *Manager) CurrentScript() *FunctionsScript

CurrentScript 返回当前激活的 functions.go 脚本,nil 表示无脚本。

func (*Manager) CurrentWithPreview

func (m *Manager) CurrentWithPreview(ctx context.Context, previewName string) *Theme

CurrentWithPreview 返回预览主题(如果 previewName 有效),否则返回当前激活主题。 previewName 为空时等同于 Current()。

func (*Manager) Delete

func (m *Manager) Delete(name string) error

Delete 删除指定主题。如果删除的是当前激活主题,不会自动切换。

func (*Manager) Get

func (m *Manager) Get(name string) *Theme

Get 按名称获取主题,不存在返回 nil。

func (*Manager) GetRecoveryInfo

func (m *Manager) GetRecoveryInfo() *RecoveryInfo

RecoveryInfo 返回最近一次主题加载失败的恢复信息,nil 表示一切正常。

func (*Manager) Install

func (m *Manager) Install(dir string) (*Theme, error)

Install 从已解压的目录安装主题。dir 是主题根目录(含 theme.yaml)。 安装过程:校验 → 暂存复制 → 备份旧目录 → 原子替换。

func (*Manager) List

func (m *Manager) List() []*Theme

List 返回所有已安装的主题列表,按名称排序。

func (*Manager) ListThemeFiles

func (m *Manager) ListThemeFiles(name string) ([]ThemeFile, error)

ListThemeFiles 列出主题目录下的所有可编辑文件。

func (*Manager) LoadPreviewTheme

func (m *Manager) LoadPreviewTheme(name string) error

LoadPreviewTheme 加载预览主题的模板到 Renderer 的独立缓存,不影响主模板。

func (*Manager) LoadTheme

func (m *Manager) LoadTheme(ctx context.Context, name string) error

LoadTheme 加载指定主题:模板 + functions.go。 任一步骤失败则自动回退到默认主题。 name 为空时加载当前激活的主题。 返回 nil 表示加载成功;返回 error 表示已回退到默认主题。

func (*Manager) LoadTranslations

func (m *Manager) LoadTranslations() error

LoadTranslations 加载所有已安装主题自带的翻译文件。

func (*Manager) RebuildTranslations

func (m *Manager) RebuildTranslations() error

RebuildTranslations 重新构建应用域和所有主题域的翻译映射。 适用于主题安装/删除后清理失效 domain,同时保留当前 locale 配置。

func (*Manager) ReloadCurrentTheme

func (m *Manager) ReloadCurrentTheme(ctx context.Context) error

ReloadCurrentTheme 重新加载当前激活的主题(文件编辑器保存后调用)。

func (*Manager) SetHookRegistry

func (m *Manager) SetHookRegistry(reg hook.Registry)

SetHookRegistry 设置共享 Hook Registry(启动时调用一次,之后只读)。

func (*Manager) SetLogger

func (m *Manager) SetLogger(log *slog.Logger)

SetLogger 设置日志记录器。

func (*Manager) SetPluginWidgetsProvider

func (m *Manager) SetPluginWidgetsProvider(provider hook.WidgetDeclProvider)

SetPluginWidgetsProvider 设置插件小组件声明提供者(启动时调用一次,之后只读)。

func (*Manager) ThemeDir

func (m *Manager) ThemeDir(name string) string

ThemeDir 返回指定主题的根目录路径。

func (*Manager) ThemeFilePath

func (m *Manager) ThemeFilePath(name, relPath string) (string, error)

ThemeFilePath 校验并返回主题文件的安全路径。 防止路径穿越攻击。

func (*Manager) ThemesDir

func (m *Manager) ThemesDir() string

ThemesDir 返回主题存放目录路径。

func (*Manager) WidgetDecls

func (m *Manager) WidgetDecls(ctx context.Context, t *Theme, area string) []WidgetDecl

WidgetDecls 返回当前主题可用组件声明,并追加当前启用插件声明的小组件。

type MenuConfigItem struct {
	ID       string `json:"id"`
	Type     string `json:"type"`
	PostID   uint   `json:"post_id,omitempty"`
	Title    string `json:"title,omitempty"`
	URL      string `json:"url,omitempty"`
	ParentID string `json:"parent_id,omitempty"`
	Target   string `json:"target,omitempty"`
	Order    int    `json:"order,omitempty"`
}

MenuConfigItem 是后台保存的菜单配置项,采用扁平结构便于表单编辑。

func ParseMenuConfig

func ParseMenuConfig(raw string) []MenuConfigItem
type MenuItem struct {
	ID       string
	Title    string
	URL      string
	Target   string
	Children []MenuItem
}

MenuItem 是模板渲染用的菜单树节点。

func BuildMenuTree

func BuildMenuTree(config []MenuConfigItem, pages map[uint]model.Post) []MenuItem
func MenuItemsFromPages(pages []model.Post) []MenuItem

func ResolveMenuItems

func ResolveMenuItems(raw string, fallbackPages []model.Post) []MenuItem
type MenuLocation struct {
	Name        string `yaml:"name" json:"name"`
	Description string `yaml:"description" json:"description"`
}

MenuLocation 描述一个主题菜单位置。

type MenuLocationEntries []MenuLocationEntry

MenuLocationEntries 是有序的菜单位置列表,UnmarshalYAML 保留 YAML mapping 的 key 顺序。

func (e *MenuLocationEntries) UnmarshalYAML(value *yaml.Node) error
type MenuLocationEntry struct {
	Key string
	MenuLocation
}

MenuLocationEntry 是带 key 的菜单位置条目,用于保留主题声明的顺序。

type OptionDecl

type OptionDecl = hook.OptionDecl

以下类型别名指向 hook 包,避免各包重复定义。

type RecoveryInfo

type RecoveryInfo struct {
	FailedTheme string
	Error       string
}

RecoveryInfo 记录主题加载失败时的恢复信息。

type SelectOpt

type SelectOpt = hook.SelectOpt

type TemplateWidget

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

TemplateWidget 是基于模板渲染的组件适配器,内置组件和主题组件使用此实现。

func NewTemplateWidget

func NewTemplateWidget(decl hook.WidgetDecl) *TemplateWidget

NewTemplateWidget 创建模板型组件。

func (*TemplateWidget) Meta

func (w *TemplateWidget) Meta() hook.WidgetDecl

func (*TemplateWidget) Render

func (w *TemplateWidget) Render(ctx context.Context, tpl *template.Template, instance hook.WidgetInstance, data any) (template.HTML, error)

type Theme

type Theme struct {
	Name        string `yaml:"name" json:"name"`
	Version     string `yaml:"version" json:"version"`
	Description string `yaml:"description" json:"description"`
	Author      string `yaml:"author" json:"author"`
	// Screenshot 是主题目录内的截图文件名(如 screenshot.png),为空表示无截图。
	Screenshot string `yaml:"screenshot" json:"screenshot"`
	// ThemeURI 是主题主页 URL。
	ThemeURI string `yaml:"theme_uri" json:"theme_uri"`
	// AuthorURI 是作者主页 URL。
	AuthorURI string `yaml:"author_uri" json:"author_uri"`
	// License 是许可证名称(如 MIT、GPL-2.0)。
	License string `yaml:"license" json:"license"`
	// LicenseURI 是许可证全文 URL。
	LicenseURI string `yaml:"license_uri" json:"license_uri"`
	// Tags 是主题标签列表。
	Tags []string `yaml:"tags" json:"tags"`
	// Dir 是主题在磁盘上的根目录(如 themes/default),由 Manager 填充。
	Dir string `yaml:"-" json:"-"`
	// WidgetAreas 是主题声明的组件区域。
	WidgetAreas map[string]WidgetArea `yaml:"widget_areas" json:"widget_areas"`
	// MenuLocations 是主题声明的菜单位置,如 primary/footer,顺序与 theme.yaml 声明一致。
	MenuLocations MenuLocationEntries `yaml:"menu_locations" json:"menu_locations"`
	// Widgets 是主题声明的可用组件列表。
	Widgets []WidgetDecl `yaml:"widgets" json:"widgets"`
	// Options 是主题声明的全局可配置选项。
	Options []hook.OptionDecl `yaml:"options" json:"options"`
	// WidgetTemplates 是主题 widgets/ 目录中实际存在的组件模板 ID 集合。
	WidgetTemplates map[string]bool `yaml:"-" json:"-"`
}

Theme 表示一个已安装的主题。

func LoadTheme

func LoadTheme(dir string) (*Theme, error)

LoadTheme 从目录加载 theme.yaml 并返回 Theme。

func (*Theme) AssetsDir

func (t *Theme) AssetsDir() string

AssetsDir 返回主题的静态资源目录路径。

func (*Theme) HasAssets

func (t *Theme) HasAssets() bool

HasAssets 检查主题是否包含静态资源目录。

func (*Theme) HasTemplates

func (t *Theme) HasTemplates() bool

HasTemplates 检查主题是否包含模板目录。

func (*Theme) I18nDir

func (t *Theme) I18nDir() string

I18nDir 返回主题自带翻译文件目录路径。

func (*Theme) LoadTranslations

func (t *Theme) LoadTranslations() error

LoadTranslations 把主题 i18n 目录绑定到主题名称对应的文本域。

func (*Theme) ScreenshotURL

func (t *Theme) ScreenshotURL() string

ScreenshotURL 返回主题截图的访问 URL,无截图时返回空字符串。

func (*Theme) TemplatesDir

func (t *Theme) TemplatesDir() string

TemplatesDir 返回主题的模板目录路径。

func (*Theme) ThemeDomain

func (t *Theme) ThemeDomain() string

ThemeDomain 返回主题翻译使用的文本域名(加 theme_ 前缀避免与应用默认域冲突)。

func (*Theme) WidgetsDir

func (t *Theme) WidgetsDir() string

WidgetsDir 返回主题的组件模板目录路径。

type ThemeFile

type ThemeFile struct {
	Path string `json:"path"`
	Size int64  `json:"size"`
}

ThemeFile 表示主题中的一个可编辑文件。

type WidgetArea

type WidgetArea struct {
	Name        string `yaml:"name" json:"name"`
	Description string `yaml:"description" json:"description"`
}

WidgetArea 描述一个可配置的组件区域。

type WidgetConfigItem

type WidgetConfigItem struct {
	InstanceID string            `json:"instance_id,omitempty"`
	ID         string            `json:"id"`
	Source     string            `json:"source,omitempty"`
	Opts       map[string]string `json:"opts,omitempty"`
}

WidgetConfigItem 是组件配置对象数组中的一个条目。

func ParseWidgetConfig

func ParseWidgetConfig(userConfigJSON string) []WidgetConfigItem

ParseWidgetConfig 解析用户配置 JSON。

type WidgetDecl

type WidgetDecl = hook.WidgetDecl

WidgetDecl 是 hook.WidgetDecl 的别名,描述主题声明的一个可用组件。

func WidgetDeclsWithBuiltins

func WidgetDeclsWithBuiltins(t *Theme) []WidgetDecl

WidgetDeclsWithBuiltins 返回主题组件声明与内置组件声明的合并结果。

func WidgetDeclsWithPlugins

func WidgetDeclsWithPlugins(t *Theme, pluginWidgets []WidgetDecl) []WidgetDecl

WidgetDeclsWithPlugins 返回主题、内置和当前启用插件的组件声明列表。

type WidgetInfo

type WidgetInfo = render.WidgetInfo

WidgetInfo 渲染时使用的组件信息。

func ResolveWidgetsWithDecls

func ResolveWidgetsWithDecls(ctx context.Context, userConfigJSON string, t *Theme, area string, decls []WidgetDecl) []WidgetInfo

ResolveWidgetsWithDecls 根据用户配置和已过滤的组件声明解析区域组件列表。

Jump to

Keyboard shortcuts

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