refactor: Remove pkg/help (#25)

The help package has been moved to its own repository at Snider/help. This commit removes the local copy of the package from this repository and updates the dependencies.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This commit is contained in:
Snider 2025-11-13 14:28:41 +00:00 committed by GitHub
parent 1c10c3dff3
commit 623f05ffc1
18 changed files with 1 additions and 859 deletions

View file

@ -1,22 +0,0 @@
:root {
--md-primary-fg-color: #00aaff;
--md-primary-fg-color--light: #00aaff;
--md-primary-fg-color--dark: #00aaff;
}
[data-md-color-scheme="slate"] {
--md-default-fg-color: hsla(0, 0%, 100%, 0.7);
--md-default-fg-color--light: hsla(0, 0%, 100%, 0.54);
--md-default-fg-color--lighter: hsla(0, 0%, 100%, 0.32);
--md-default-fg-color--lightest: hsla(0, 0%, 100%, 0.12);
--md-default-bg-color: #0d0d0d;
--md-default-bg-color--light: #1a1a1a;
--md-default-bg-color--lighter: #333333;
--md-default-bg-color--lightest: #4f4f4f;
--md-code-fg-color: hsla(0, 0%, 100%, 0.7);
--md-code-bg-color: #1a1a1a;
--md-accent-fg-color: #00aaff;
}

View file

@ -1,116 +0,0 @@
package help
import (
"context"
"embed"
"fmt"
"github.com/Snider/Core/pkg/core"
"github.com/wailsapp/wails/v3/pkg/application"
)
//go:embed all:public/*
var helpStatic embed.FS
// Options holds configuration for the help service.
type Options struct{}
// Service manages the in-app help system.
type Service struct {
*core.Runtime[Options]
config core.Config
display core.Display
assets embed.FS
}
// newHelpService contains the common logic for initialising a Service struct.
func newHelpService() (*Service, error) {
return &Service{
assets: helpStatic,
}, nil
}
// New is the constructor for static dependency injection.
// It creates a Service instance without initialising the core.Runtime field.
// Dependencies are passed directly here.
func New() (*Service, error) {
s, err := newHelpService()
if err != nil {
return nil, err
}
return s, nil
}
// Register is the constructor for dynamic dependency injection (used with core.WithService).
// It creates a Service instance and initialises its core.Runtime field.
// Dependencies are injected during ServiceStartup.
func Register(c *core.Core) (any, error) {
s, err := newHelpService()
if err != nil {
return nil, err
}
s.Runtime = core.NewRuntime(c, Options{})
return s, nil
}
// HandleIPCEvents processes IPC messages, including injecting dependencies on startup.
func (s *Service) HandleIPCEvents(c *core.Core, msg core.Message) error {
switch m := msg.(type) {
case core.ActionServiceStartup:
return s.ServiceStartup(context.Background(), application.ServiceOptions{})
default:
c.App.Logger.Error("Help: Unknown message type", "type", fmt.Sprintf("%T", m))
}
return nil
}
// ServiceStartup is called when the app starts, after dependencies are injected.
func (s *Service) ServiceStartup(context.Context, application.ServiceOptions) error {
s.Core().App.Logger.Info("Help service started")
return nil
}
// Show displays the help window.
func (s *Service) Show() error {
if s.display == nil {
return fmt.Errorf("display service not initialized")
}
if s.Core() == nil {
return fmt.Errorf("core runtime not initialized")
}
msg := map[string]any{
"action": "display.open_window",
"name": "help",
"options": map[string]any{
"Title": "Help",
"Width": 800,
"Height": 600,
},
}
return s.Core().ACTION(msg)
}
// ShowAt displays a specific section of the help documentation.
func (s *Service) ShowAt(anchor string) error {
if s.display == nil {
return fmt.Errorf("display service not initialized")
}
if s.Core() == nil {
return fmt.Errorf("core runtime not initialized")
}
msg := map[string]any{
"action": "display.open_window",
"name": "help",
"options": map[string]any{
"Title": "Help",
"Width": 800,
"Height": 600,
"URL": fmt.Sprintf("/#%s", anchor),
},
}
return s.Core().ACTION(msg)
}
// Ensure Service implements the core.Help interface.
var _ core.Help = (*Service)(nil)

View file

@ -1,103 +0,0 @@
package help
import (
"testing"
"github.com/Snider/Core/pkg/core"
"github.com/stretchr/testify/assert"
"github.com/wailsapp/wails/v3/pkg/application"
)
// MockDisplay is a mock implementation of the core.Display interface.
type MockDisplay struct {
ShowCalled bool
}
func (m *MockDisplay) Show() error {
m.ShowCalled = true
return nil
}
func (m *MockDisplay) ShowAt(anchor string) error {
m.ShowCalled = true
return nil
}
func (m *MockDisplay) Hide() error { return nil }
func (m *MockDisplay) HideAt(anchor string) error { return nil }
func (m *MockDisplay) OpenWindow(opts ...core.WindowOption) error { return nil }
// MockCore is a mock implementation of the *core.Core type.
type MockCore struct {
Core *core.Core
ActionCalled bool
ActionMsg core.Message
}
// ACTION matches the signature required by RegisterAction.
func (m *MockCore) ACTION(c *core.Core, msg core.Message) error {
m.ActionCalled = true
m.ActionMsg = msg
return nil
}
func setupService(t *testing.T) (*Service, *MockCore, *MockDisplay) {
s, err := New()
assert.NoError(t, err)
app := application.New(application.Options{})
c, err := core.New(core.WithWails(app))
assert.NoError(t, err)
mockCore := &MockCore{Core: c}
mockDisplay := &MockDisplay{}
s.Runtime = core.NewRuntime(c, Options{})
s.display = mockDisplay
// Register our mock handler. When the real s.Core().ACTION is called,
// our mock handler will be executed.
c.RegisterAction(mockCore.ACTION)
return s, mockCore, mockDisplay
}
func TestNew(t *testing.T) {
s, err := New()
assert.NoError(t, err)
assert.NotNil(t, s)
}
func TestShow(t *testing.T) {
s, mockCore, _ := setupService(t)
err := s.Show()
assert.NoError(t, err)
assert.True(t, mockCore.ActionCalled)
msg, ok := mockCore.ActionMsg.(map[string]any)
assert.True(t, ok)
assert.Equal(t, "display.open_window", msg["action"])
assert.Equal(t, "help", msg["name"])
}
func TestShowAt(t *testing.T) {
s, mockCore, _ := setupService(t)
err := s.ShowAt("test-anchor")
assert.NoError(t, err)
assert.True(t, mockCore.ActionCalled)
msg, ok := mockCore.ActionMsg.(map[string]any)
assert.True(t, ok)
assert.Equal(t, "display.open_window", msg["action"])
assert.Equal(t, "help", msg["name"])
opts, ok := msg["options"].(map[string]any)
assert.True(t, ok)
assert.Equal(t, "/#test-anchor", opts["URL"])
}
func TestHandleIPCEvents_ServiceStartup(t *testing.T) {
s, _, _ := setupService(t)
err := s.HandleIPCEvents(s.Core(), core.ActionServiceStartup{})
assert.NoError(t, err)
}

View file

@ -1,121 +0,0 @@
site_name: Core.Help
site_url: https://dappco.re
repo_url: https://github.com/Snider/Core
edit_uri: edit/main/docs/src/
docs_dir: src
nav:
- Overview: index.md
- Core: core/index.md
- Config: core/config.md
- Crypt: core/crypt.md
- Display: core/display.md
- Help: core/help.md
- IO: core/io.md
- Workspace: core/workspace.md
copyright: Core &copy; EUPL-1.2 &mdash; 2024 to &infin; and beyond
theme:
name: material
palette:
# Palette toggle for dark mode
- scheme: slate
primary: blue
accent: blue
toggle:
icon: material/brightness-4
name: Switch to light mode
# Palette toggle for light mode
- scheme: default
primary: blue
accent: blue
toggle:
icon: material/brightness-7
name: Switch to dark mode
font:
text: "Roboto"
code: "Roboto Mono"
language: en
icon:
repo: fontawesome/brands/git-alt
edit: material/pencil
view: material/eye
features:
- navigation.instant
- navigation.tracking
- navigation.tabs
- navigation.indexes
- navigation.expand
- navigation.sections
- navigation.path
- navigation.top
- search.suggest
- search.highlight
- search.share
- content.tabs.link
- content.code.copy
extra:
generator: false
social:
- icon: fontawesome/brands/github
link: https://github.com/Snider/Core
- icon: fontawesome/solid/globe
link: https://dappco.re
extra_css:
- assets/stylesheets/extra.css
plugins:
- offline:
- privacy:
- group:
enabled: !ENV CI
plugins:
- git-revision-date-localized:
type: timeago
enable_creation_date: true
fallback_to_build_date: true
tz: Europe/London
- git-committers:
- group:
enabled: !ENV INSIDERS
plugins:
- optimise
- search:
lang:
- en
markdown_extensions:
- abbr
- admonition
- attr_list
- def_list
- footnotes
- meta
- toc:
permalink: true
- tables
- md_in_html
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.snippets
- pymdownx.details
- pymdownx.superfences:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format
- pymdownx.betterem
- pymdownx.tabbed:
alternate_style: true
- pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg

View file

@ -1 +0,0 @@
mkdocs-material

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 695 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 756 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View file

@ -1,78 +0,0 @@
---
title: Core.Help
---
# Overview
Core is an opinionated framework for building Go desktop apps with Wails, providing a small set of focused modules you can mix into your app. It ships with sensible defaults and a demo app that doubles as inapp help.
- Site: [https://dappco.re](https://dappco.re)
- Repo: [https://github.com/Snider/Core](https://github.com/Snider/Core)
## Modules
- Core — framework bootstrap and service container
- Core.Config — app and UI state persistence
- Core.Crypt — keys, encrypt/decrypt, sign/verify
- Core.Display — windows, tray, window state
- Core.Help — inapp help and deeplinks
- Core.IO — local/remote filesystem helpers
- Core.Workspace — projects and paths
## Quick start
```go
package main
import (
"github.com/wailsapp/wails/v3/pkg/application"
core "github.com/Snider/Core"
)
func main() {
app := core.New(
core.WithServiceLock(),
)
wailsApp := application.NewWithOptions(&application.Options{
Bind: []interface{}{app},
})
wailsApp.Run()
}
```
## Services
```go
package demo
import (
core "github.com/Snider/Core"
)
// Register your service
func Register(c *core.Core) error {
return c.RegisterService("demo", &Demo{core: c})
}
```
## Display example
```go
package display
import (
"context"
"github.com/wailsapp/wails/v3/pkg/application"
)
// Open a window on startup
func (d *API) ServiceStartup(ctx context.Context, _ application.ServiceOptions) error {
d.OpenWindow(
OptName("main"),
OptHeight(900),
OptWidth(1280),
OptURL("/"),
OptTitle("Core"),
)
return nil
}
```
See the left nav for detailed pages on each module.

View file

@ -1,367 +0,0 @@
[data-md-color-scheme="lethean"] {
--md-primary-fg-color: #0F131C;
}
.hero-section {
background: linear-gradient(135deg, #0F131C 0%, #1a237e 100%);
color: white;
padding: 4rem 2rem;
text-align: center;
margin-bottom: 3rem;
}
.hero-content {
max-width: 800px;
margin: 0 auto;
}
.hero-content h1 {
font-size: 2.5rem;
margin-bottom: 1rem;
color: white;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
.hero-subtitle {
font-size: 1.25rem;
margin-bottom: 2rem;
opacity: 0.9;
}
.hero-badges {
margin-bottom: 2rem;
}
.badge {
background: rgba(255, 255, 255, 0.1);
padding: 0.5rem 1rem;
border-radius: 20px;
margin: 0 0.5rem;
font-size: 0.9rem;
}
.cta-button {
display: inline-block;
background: #4A90E2;
color: white;
padding: 0.8rem 2rem;
border-radius: 4px;
text-decoration: none;
font-weight: 500;
transition: background 0.3s, transform 0.3s;
}
.cta-button:hover {
background: #357ABD;
color: white;
transform: translateY(-2px);
}
.cta-button.secondary {
background: transparent;
border: 2px solid #4A90E2;
color: #4A90E2;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 0.2rem;
padding: 0.2rem;
margin-bottom: 3rem;
}
.feature-card {
background: white;
border-radius: 8px;
padding: 1.0rem;
border: 2px solid #e2e8f0;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: all 0.3s;
}
[data-md-color-scheme="slate"] .feature-card {
background: #2d3748;
border-color: #4a5568;
color: #e2e8f0;
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
}
.feature-card img {
width: 100%;
height: 150px;
object-fit: cover;
border-radius: 4px;
margin-bottom: 1rem;
}
.feature-card h3 {
margin: 1rem 0;
color: #0F131C;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
[data-md-color-scheme="slate"] .feature-card h3 {
color: #e2e8f0;
}
.get-started {
color: #4A90E2;
text-decoration: none;
font-weight: 500;
}
.benefits-section {
background: #f5f5f5;
padding: 0.4rem 0.2rem;
text-align: center;
margin-bottom: 3rem;
}
.benefits-section h2 {
font-size: 1.5rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 0.5rem;
margin-top: 0.8rem;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
[data-md-color-scheme="slate"] .benefits-section {
background: #1a202c;
color: #e2e8f0;
}
.benefits-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0.2rem;
padding: 0.2rem;
margin: 0.2rem auto;
}
.benefit-card {
background: white;
padding: 0.5rem;
border-radius: 8px;
border: 2px solid #e2e8f0;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
text-align: left;
}
[data-md-color-scheme="slate"] .benefit-card {
background: #2d3748;
border-color: #4a5568;
color: #e2e8f0;
}
.roadmap-section {
padding: 0.4rem 0.2rem;
max-width: 1200px;
margin: 0 auto;
}
.timeline {
position: relative;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 2rem;
margin: 2rem 0;
}
.timeline-item {
background: white;
padding: 1.5rem;
border-radius: 8px;
border: 2px solid #e2e8f0;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
position: relative;
transition: all 0.3s;
}
.timeline-item.completed {
grid-column: span 2;
}
[data-md-color-scheme="slate"] .timeline-item {
background: #2d3748;
border-color: #4a5568;
color: #e2e8f0;
}
.timeline-item:hover {
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
}
.timeline-marker {
width: 20px;
height: 20px;
border-radius: 50%;
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
}
.timeline-item.planning .timeline-marker {
background: #718096;
}
.timeline-item.in-progress .timeline-marker {
background: #4A90E2;
}
.timeline-item.completed .timeline-marker {
background: #48BB78;
}
.timeline-item ul {
list-style: none;
padding: 0;
}
.timeline-item li {
margin: 0.5rem 0;
padding-left: 24px;
position: relative;
}
.timeline-item li::before {
content: "";
width: 12px;
height: 12px;
border-radius: 50%;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
}
.timeline-item li.planned::before {
background: #718096;
}
.timeline-item li.active::before {
background: #4A90E2;
}
.timeline-item li.completed::before {
background: #48BB78;
}
.timeline-item li ul {
margin-top: 0.5rem;
margin-left: 1rem;
}
.timeline-item li ul li {
font-size: 0.9rem;
margin: 0.25rem 0;
}
.timeline-item li ul li::before {
width: 8px;
height: 8px;
background: #a0aec0;
}
.timeline-item li ul li a {
color: #4A90E2;
text-decoration: none;
font-weight: 500;
}
.timeline-item li ul li a:hover {
color: #357ABD;
text-decoration: underline;
}
[data-md-color-scheme="slate"] .timeline-item li ul li a {
color: #63b3ed;
}
[data-md-color-scheme="slate"] .timeline-item li ul li a:hover {
color: #90cdf4;
}
.date {
font-size: 0.8rem;
color: #718096;
margin-left: 0.5rem;
}
[data-md-color-scheme="slate"] .date {
color: #a0aec0;
}
.cta-section {
background: #0F131C;
color: white;
padding: 4rem 2rem;
text-align: center;
margin-bottom: 3rem;
}
.cta-buttons {
display: flex;
gap: 1rem;
justify-content: center;
margin-top: 2rem;
}
.community-section {
padding: 4rem 2rem;
text-align: center;
}
.community-links {
display: flex;
gap: 2rem;
justify-content: center;
margin-top: 2rem;
}
.community-link {
color: #4A90E2;
text-decoration: none;
font-weight: 500;
transition: all 0.3s;
}
.community-link:hover {
color: #357ABD;
transform: translateY(-2px);
}
@media (max-width: 768px) {
.hero-content h1 {
font-size: 2rem;
}
.timeline {
grid-template-columns: 1fr;
}
.timeline-item.completed {
grid-column: auto;
}
.features-grid {
grid-template-columns: 1fr;
}
.cta-buttons {
flex-direction: column;
}
.community-links {
flex-direction: column;
gap: 1rem;
}
}

View file

@ -1,36 +0,0 @@
version: '3'
tasks:
default:
cmds:
- task: dev
desc: "Start the development server."
install:
cmds:
- pip install -r requirements.txt
desc: "Install documentation dependencies."
status:
- test -f requirements.txt
dev:
run: always
cmds:
- mkdocs serve -o -c -w src -w mkdocs.yml
desc: "Start the live-reloading documentation server."
sources:
- mkdocs.yml
- "src/**/*"
- "src/**/*.css"
generates:
- "public/**/*"
build:
cmds:
- mkdocs build --clean -d public
desc: "Build the static documentation site."
deploy:
desc: "Deploy the documentation to GitHub Pages."
cmds:
- mkdocs gh-deploy --force

View file

@ -8,7 +8,6 @@ import (
"github.com/Snider/Core/pkg/core"
"github.com/Snider/Core/pkg/crypt"
"github.com/Snider/Core/pkg/display"
"github.com/Snider/Core/pkg/help"
"github.com/Snider/Core/pkg/i18n"
"github.com/Snider/Core/pkg/workspace"
"github.com/wailsapp/wails/v3/pkg/application"
@ -21,7 +20,6 @@ type Runtime struct {
Core *core.Core
Config *config.Service
Display *display.Service
Help *help.Service
Crypt *crypt.Service
I18n *i18n.Service
Workspace *workspace.Service
@ -37,7 +35,7 @@ func NewWithFactories(app *application.App, factories map[string]ServiceFactory)
core.WithWails(app),
}
for _, name := range []string{"config", "display", "help", "crypt", "i18n", "workspace"} {
for _, name := range []string{"config", "display", "crypt", "i18n", "workspace"} {
factory, ok := factories[name]
if !ok {
return nil, fmt.Errorf("service %s factory not provided", name)
@ -65,10 +63,6 @@ func NewWithFactories(app *application.App, factories map[string]ServiceFactory)
if !ok {
return nil, fmt.Errorf("display service has unexpected type")
}
helpSvc, ok := services["help"].(*help.Service)
if !ok {
return nil, fmt.Errorf("help service has unexpected type")
}
cryptSvc, ok := services["crypt"].(*crypt.Service)
if !ok {
return nil, fmt.Errorf("crypt service has unexpected type")
@ -87,7 +81,6 @@ func NewWithFactories(app *application.App, factories map[string]ServiceFactory)
Core: coreInstance,
Config: configSvc,
Display: displaySvc,
Help: helpSvc,
Crypt: cryptSvc,
I18n: i18nSvc,
Workspace: workspaceSvc,
@ -101,7 +94,6 @@ func New(app *application.App) (*Runtime, error) {
return NewWithFactories(app, map[string]ServiceFactory{
"config": func() (any, error) { return config.New() },
"display": func() (any, error) { return display.New() },
"help": func() (any, error) { return help.New() },
"crypt": func() (any, error) { return crypt.New() },
"i18n": func() (any, error) { return i18n.New() },
"workspace": func() (any, error) { return workspace.New() },

View file

@ -7,7 +7,6 @@ import (
"github.com/Snider/Core/pkg/config"
"github.com/Snider/Core/pkg/crypt"
"github.com/Snider/Core/pkg/display"
"github.com/Snider/Core/pkg/help"
"github.com/Snider/Core/pkg/i18n"
"github.com/Snider/Core/pkg/runtime"
"github.com/Snider/Core/pkg/workspace"
@ -30,7 +29,6 @@ func TestNew(t *testing.T) {
factories: map[string]runtime.ServiceFactory{
"config": func() (any, error) { return &config.Service{}, nil },
"display": func() (any, error) { return &display.Service{}, nil },
"help": func() (any, error) { return &help.Service{}, nil },
"crypt": func() (any, error) { return &crypt.Service{}, nil },
"i18n": func() (any, error) { return &i18n.Service{}, nil },
"workspace": func() (any, error) { return &workspace.Service{}, nil },
@ -41,7 +39,6 @@ func TestNew(t *testing.T) {
assert.NotNil(t, rt.Core)
assert.NotNil(t, rt.Config)
assert.NotNil(t, rt.Display)
assert.NotNil(t, rt.Help)
assert.NotNil(t, rt.Crypt)
assert.NotNil(t, rt.I18n)
assert.NotNil(t, rt.Workspace)
@ -53,7 +50,6 @@ func TestNew(t *testing.T) {
factories: map[string]runtime.ServiceFactory{
"config": func() (any, error) { return &config.Service{}, nil },
"display": func() (any, error) { return &display.Service{}, nil },
"help": func() (any, error) { return &help.Service{}, nil },
"crypt": func() (any, error) { return nil, errors.New("crypt service failed") },
"i18n": func() (any, error) { return &i18n.Service{}, nil },
"workspace": func() (any, error) { return &workspace.Service{}, nil },
@ -67,7 +63,6 @@ func TestNew(t *testing.T) {
factories: map[string]runtime.ServiceFactory{
"config": func() (any, error) { return &config.Service{}, nil },
"display": func() (any, error) { return "not a display service", nil },
"help": func() (any, error) { return &help.Service{}, nil },
"crypt": func() (any, error) { return &crypt.Service{}, nil },
"i18n": func() (any, error) { return &i18n.Service{}, nil },
"workspace": func() (any, error) { return &workspace.Service{}, nil },
@ -81,7 +76,6 @@ func TestNew(t *testing.T) {
factories: map[string]runtime.ServiceFactory{
"config": func() (any, error) { return &config.Service{}, nil },
"display": func() (any, error) { return &display.Service{}, nil },
"help": func() (any, error) { return &help.Service{}, nil },
"crypt": func() (any, error) { return &crypt.Service{}, nil },
"i18n": func() (any, error) { return &i18n.Service{}, nil },
"workspace": func() (any, error) { return &workspace.Service{}, nil },