sitepress 5.0.0.beta1 → 5.0.0.beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/exe/sitepress +2 -1
- data/lib/sitepress/application.rb +61 -0
- data/lib/sitepress/application_server.rb +72 -0
- data/lib/sitepress/cli/plugin_helpers.rb +59 -0
- data/lib/sitepress/cli.rb +173 -0
- data/lib/sitepress/plugins.rb +76 -0
- data/lib/sitepress/project_template.rb +18 -0
- data/lib/sitepress/repl.rb +29 -0
- data/lib/sitepress.rb +17 -0
- data/rails/app/assets/config/manifest.js +0 -0
- data/rails/app/controllers/application_controller.rb +2 -0
- data/rails/app/controllers/site_controller.rb +62 -0
- data/rails/app/helpers/application_helper.rb +27 -0
- data/rails/app/views/layouts/sitepress.html.erb +21 -0
- data/rails/app/views/layouts/sitepress_error.html.erb +21 -0
- data/rails/app/views/site/_copy_button.html.erb +7 -0
- data/rails/app/views/site/_footer.html.erb +1 -0
- data/rails/app/views/site/_stack_trace.html.erb +48 -0
- data/rails/app/views/site/action_template_error.html.erb +48 -0
- data/rails/app/views/site/not_found.html.erb +39 -0
- data/rails/app/views/site/parse_error.html.erb +40 -0
- data/rails/app/views/site/standard_error.html.erb +30 -0
- data/rails/public/_sitepress/images/logo-dark.svg +13 -0
- data/rails/public/_sitepress/images/logo.svg +13 -0
- data/rails/public/_sitepress/javascripts/error.js +60 -0
- data/rails/public/_sitepress/stylesheets/site.css +464 -0
- data/sitepress.gemspec +11 -2
- data/templates/default/.gitignore +1 -0
- data/templates/default/Gemfile.tt +17 -0
- data/templates/default/README.md +75 -0
- data/templates/default/Rakefile +29 -0
- data/templates/default/assets/images/logo-brown.svg +13 -0
- data/templates/default/assets/images/logo-white.svg +13 -0
- data/templates/default/assets/javascripts/.gitkeep +0 -0
- data/templates/default/assets/stylesheets/site.css +86 -0
- data/templates/default/components/.gitkeep +0 -0
- data/templates/default/config/site.rb +10 -0
- data/templates/default/helpers/page_helper.rb +13 -0
- data/templates/default/layouts/layout.html.erb +22 -0
- data/templates/default/pages/favicon.ico +0 -0
- data/templates/default/pages/index.html.erb +18 -0
- metadata +86 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30daa89481221dd83d4fc8041ff73e5187ea0715ca763a0d6542899fadb0f60b
|
|
4
|
+
data.tar.gz: 04d1a39f9d91d1ae2b492e2619ade8a1217395948dc66d663c8af196b2aa0ce0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1008b2d97905b6749180bf8c79b85987ffd20c219e0dc9cdbb657b2103a42ff473ea59f8bc23dd93f537b076515bd02c9291b42977b816c86f662130b273fc4c
|
|
7
|
+
data.tar.gz: d4a8406386ea5a29107c6bcadc451f094ccae768565881dca68695cb26115b938c057a469ba2caac63f9df55ee5631a1b6476447961e78158d6771b738c4d229
|
data/exe/sitepress
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require "action_controller/railtie"
|
|
2
|
+
require "propshaft"
|
|
3
|
+
require "sitepress-rails"
|
|
4
|
+
|
|
5
|
+
# Require the gems listed in Gemfile, including any gems
|
|
6
|
+
# you've limited to :test, :development, or :production.
|
|
7
|
+
Bundler.require(*Rails.groups)
|
|
8
|
+
|
|
9
|
+
# Configure the rails application for standalone Sitepress.
|
|
10
|
+
# This handles rendering pages via Rails' view layer.
|
|
11
|
+
module Sitepress
|
|
12
|
+
class Application < Rails::Application
|
|
13
|
+
# Control whether or not to display friendly error reporting messages
|
|
14
|
+
# in Sitepress. The development server turns this on an handles exception,
|
|
15
|
+
# while the compile and other environments would likely have this disabled.
|
|
16
|
+
config.enable_site_error_reporting = false
|
|
17
|
+
|
|
18
|
+
# When in a development environment, we'll want to reload the site between
|
|
19
|
+
# requests so we can see the latest changes; otherwise, load the site once
|
|
20
|
+
# and we're done.
|
|
21
|
+
config.enable_site_reloading = false
|
|
22
|
+
|
|
23
|
+
# Default to a development environment type of configuration, which would reload the site.
|
|
24
|
+
# This gets reset later depending on a preference in the `before_initialize` callback.
|
|
25
|
+
config.eager_load = true
|
|
26
|
+
config.cache_classes = true
|
|
27
|
+
|
|
28
|
+
config.before_initialize do
|
|
29
|
+
# Eager load classes, content, etc. to boost performance when site reloading is disabled.
|
|
30
|
+
config.eager_load = !config.enable_site_reloading
|
|
31
|
+
|
|
32
|
+
# Cache classes for speed in production environments when site reloading is disabled.
|
|
33
|
+
config.cache_classes = !config.enable_site_reloading
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Path that points the the Sitepress UI rails app; which displays routes, error messages.
|
|
37
|
+
# etc. to the user if `enable_site_error_reporting` is enabled.
|
|
38
|
+
config.root = File.join(File.dirname(__FILE__), "../../rails")
|
|
39
|
+
|
|
40
|
+
# Rails won't start without this.
|
|
41
|
+
config.secret_key_base = SecureRandom.uuid
|
|
42
|
+
|
|
43
|
+
# Setup routes. The `constraints` key is set to `nil` so the `SiteController` can
|
|
44
|
+
# treat a page not being found as an exception, which it then handles. If the constraint
|
|
45
|
+
# was set to the default, Sitepress would hand off routing back to rails if something isn't
|
|
46
|
+
# found and fail silently.
|
|
47
|
+
routes.append { sitepress_pages root: true, controller: "site", constraints: nil }
|
|
48
|
+
|
|
49
|
+
# Setup logger.
|
|
50
|
+
logger = ActiveSupport::Logger.new(STDOUT)
|
|
51
|
+
logger.formatter = config.log_formatter
|
|
52
|
+
config.logger = ActiveSupport::TaggedLogging.new(logger)
|
|
53
|
+
|
|
54
|
+
# Allow any host to connect to the development server. The actual binding is
|
|
55
|
+
# controlled by server in the `sitepress-cli`; not by Rails.
|
|
56
|
+
config.hosts << proc { true } if config.respond_to? :hosts
|
|
57
|
+
|
|
58
|
+
# Stand-alone boot locations
|
|
59
|
+
paths["config/initializers"] << File.expand_path("./config/initializers")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module Sitepress
|
|
2
|
+
# Development server wrapper that handles Application setup and
|
|
3
|
+
# delegates to the base Server class.
|
|
4
|
+
#
|
|
5
|
+
# This provides a simpler API for site.rb configuration:
|
|
6
|
+
#
|
|
7
|
+
# site = Sitepress::Site.new(root_path: ".")
|
|
8
|
+
# Sitepress.server = Sitepress::ApplicationServer.new(site)
|
|
9
|
+
# Sitepress.server.live_reload = true
|
|
10
|
+
# Sitepress.server.add_process :css, "tailwindcss -w ..."
|
|
11
|
+
#
|
|
12
|
+
class ApplicationServer
|
|
13
|
+
attr_reader :site, :processes
|
|
14
|
+
attr_accessor :live_reload, :host, :port
|
|
15
|
+
|
|
16
|
+
def initialize(site)
|
|
17
|
+
@site = site
|
|
18
|
+
@live_reload = false
|
|
19
|
+
@host = Server::DEFAULT_HOST
|
|
20
|
+
@port = Server::DEFAULT_PORT
|
|
21
|
+
@processes = []
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Add a labeled process to run alongside the server.
|
|
25
|
+
def add_process(label, command)
|
|
26
|
+
@processes << [label, command]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Start the server with the Sitepress Application.
|
|
30
|
+
def run
|
|
31
|
+
setup_application!
|
|
32
|
+
|
|
33
|
+
r = build_reloader if live_reload
|
|
34
|
+
|
|
35
|
+
server = Server.new(Application, reloader: r)
|
|
36
|
+
server.host = host
|
|
37
|
+
server.port = port
|
|
38
|
+
@processes.each { |label, cmd| server.add_process(label, cmd) }
|
|
39
|
+
|
|
40
|
+
puts " Site: #{site.root_path}"
|
|
41
|
+
server.run
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def setup_application!
|
|
47
|
+
require_relative "application"
|
|
48
|
+
|
|
49
|
+
Application.config.enable_site_error_reporting = true
|
|
50
|
+
Application.config.enable_site_reloading = true
|
|
51
|
+
|
|
52
|
+
# Make site available to the Rails app
|
|
53
|
+
Sitepress.configuration.site = site
|
|
54
|
+
|
|
55
|
+
Application.initialize!
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def build_reloader
|
|
59
|
+
r = Reloader.new(logger: $stdout)
|
|
60
|
+
site_watch_paths.each { |path| r.watch(path) }
|
|
61
|
+
r
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def site_watch_paths
|
|
65
|
+
[
|
|
66
|
+
site.pages_path.to_s,
|
|
67
|
+
site.helpers_path.to_s,
|
|
68
|
+
site.assets_path.to_s
|
|
69
|
+
].select { |p| File.directory?(p) }
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require "thor"
|
|
2
|
+
|
|
3
|
+
module Sitepress
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
# Helpers for CLI plugin commands.
|
|
6
|
+
#
|
|
7
|
+
# Include this module in your plugin's Thor class to get access
|
|
8
|
+
# to Sitepress configuration, site, and Rails environment.
|
|
9
|
+
#
|
|
10
|
+
# Example:
|
|
11
|
+
#
|
|
12
|
+
# class Sitepress::Deploy::CLI < Thor
|
|
13
|
+
# include Sitepress::CLI::PluginHelpers
|
|
14
|
+
#
|
|
15
|
+
# desc "s3", "Deploy to S3"
|
|
16
|
+
# def s3
|
|
17
|
+
# initialize! # Boot Rails/Sitepress
|
|
18
|
+
# site.resources.each { |r| upload(r) }
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
module PluginHelpers
|
|
23
|
+
# Boot the Rails/Sitepress environment.
|
|
24
|
+
# Call this at the start of commands that need access to the site.
|
|
25
|
+
#
|
|
26
|
+
# @yield [app] Optional block to configure the app before initialization
|
|
27
|
+
def initialize!(&block)
|
|
28
|
+
require File.expand_path("../boot", __dir__)
|
|
29
|
+
app.tap(&block) if block_given?
|
|
30
|
+
app.initialize! unless app.initialized?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# The Sitepress::Server Rails application.
|
|
34
|
+
def app
|
|
35
|
+
Sitepress::Server
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# The Sitepress configuration object.
|
|
39
|
+
def configuration
|
|
40
|
+
Sitepress.configuration
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# The configured Site instance.
|
|
44
|
+
def site
|
|
45
|
+
configuration.site
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# The parent Rails engine (Sitepress::Server or host app).
|
|
49
|
+
def rails
|
|
50
|
+
configuration.parent_engine
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# The Rails logger.
|
|
54
|
+
def logger
|
|
55
|
+
rails.config.logger
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
require "thor"
|
|
2
|
+
require "fileutils"
|
|
3
|
+
|
|
4
|
+
module Sitepress
|
|
5
|
+
# Command line interface for Sitepress sites.
|
|
6
|
+
class CLI < Thor
|
|
7
|
+
# Default build path for compiler.
|
|
8
|
+
COMPILE_TARGET_PATH = "./build".freeze
|
|
9
|
+
|
|
10
|
+
# Site configuration file
|
|
11
|
+
SITE_CONFIG_PATH = "config/site.rb".freeze
|
|
12
|
+
|
|
13
|
+
include Thor::Actions
|
|
14
|
+
|
|
15
|
+
source_root File.expand_path("../../../templates/default", __FILE__)
|
|
16
|
+
|
|
17
|
+
option :port, aliases: "-p", type: :numeric, desc: "Port to run server on"
|
|
18
|
+
option :host, aliases: "-h", type: :string, desc: "Host to bind server to"
|
|
19
|
+
desc "server", "Run development server"
|
|
20
|
+
def server
|
|
21
|
+
setup_environment!
|
|
22
|
+
load_site_config!(validate: false)
|
|
23
|
+
|
|
24
|
+
unless Sitepress.server
|
|
25
|
+
say "Error: Server not configured in #{SITE_CONFIG_PATH}", :red
|
|
26
|
+
say "Add: Sitepress.server = Sitepress::ApplicationServer.new(site)"
|
|
27
|
+
exit 1
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Override port/host if specified on command line
|
|
31
|
+
Sitepress.server.port = options[:port] if options[:port]
|
|
32
|
+
Sitepress.server.host = options[:host] if options[:host]
|
|
33
|
+
|
|
34
|
+
Sitepress.server.run
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
option :output_path, default: COMPILE_TARGET_PATH, type: :string
|
|
38
|
+
option :fail_on_error, default: false, type: :boolean
|
|
39
|
+
desc "compile", "Compile project into static pages"
|
|
40
|
+
def compile
|
|
41
|
+
setup_environment!
|
|
42
|
+
load_site_config!(validate: false)
|
|
43
|
+
setup_site_from_server!
|
|
44
|
+
initialize_rails_app!
|
|
45
|
+
|
|
46
|
+
logger.info "Sitepress compiling assets"
|
|
47
|
+
compile_assets(Pathname.new(options.fetch("output_path")).join("assets"))
|
|
48
|
+
|
|
49
|
+
logger.info "Sitepress compiling pages"
|
|
50
|
+
compiler = Compiler::Files.new \
|
|
51
|
+
site: Sitepress.site,
|
|
52
|
+
root_path: options.fetch("output_path"),
|
|
53
|
+
fail_on_error: options.fetch("fail_on_error")
|
|
54
|
+
|
|
55
|
+
begin
|
|
56
|
+
compiler.compile
|
|
57
|
+
ensure
|
|
58
|
+
logger.info ""
|
|
59
|
+
logger.info "Compilation Summary"
|
|
60
|
+
logger.info " Build path: #{compiler.root_path.expand_path}"
|
|
61
|
+
logger.info " Succeeded: #{compiler.succeeded.count}"
|
|
62
|
+
logger.info " Failed: #{compiler.failed.count}"
|
|
63
|
+
if compiler.failed.any?
|
|
64
|
+
logger.info ""
|
|
65
|
+
logger.info "Failed Resources"
|
|
66
|
+
compiler.failed.each do |resource|
|
|
67
|
+
logger.info " #{resource.request_path} #{resource.asset.path}"
|
|
68
|
+
end
|
|
69
|
+
abort
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
desc "console", "Interactive project shell"
|
|
75
|
+
def console
|
|
76
|
+
setup_environment!
|
|
77
|
+
load_site_config!(validate: false)
|
|
78
|
+
setup_site_from_server!
|
|
79
|
+
initialize_rails_app!
|
|
80
|
+
REPL.new(site: Sitepress.site).start
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
desc "new PATH", "Create new project at PATH"
|
|
84
|
+
def new(target)
|
|
85
|
+
# Peg the generated site to roughly the released version.
|
|
86
|
+
*segments, _ = Gem::Version.new(Sitepress::VERSION).segments
|
|
87
|
+
@target_sitepress_version = segments.join(".")
|
|
88
|
+
|
|
89
|
+
inside target do
|
|
90
|
+
directory self.class.source_root, "."
|
|
91
|
+
run "bundle install"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
desc "version", "Show version"
|
|
96
|
+
def version
|
|
97
|
+
say Sitepress::VERSION
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def setup_environment!
|
|
103
|
+
unless File.exist?(SITE_CONFIG_PATH)
|
|
104
|
+
say "Error: #{SITE_CONFIG_PATH} not found.", :red
|
|
105
|
+
say "Run 'sitepress new .' to create a new project in the current directory."
|
|
106
|
+
exit 1
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Set up Bundler if Gemfile exists
|
|
110
|
+
if File.exist?("Gemfile")
|
|
111
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("Gemfile")
|
|
112
|
+
require "bundler/setup"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def load_site_config!(validate: true)
|
|
117
|
+
config_path = File.expand_path(SITE_CONFIG_PATH)
|
|
118
|
+
load config_path
|
|
119
|
+
|
|
120
|
+
# Ensure site is configured (check the raw instance variable to avoid auto-creating default)
|
|
121
|
+
if validate && !Sitepress.configuration.instance_variable_get(:@site)
|
|
122
|
+
say "Error: Site not configured in #{SITE_CONFIG_PATH}", :red
|
|
123
|
+
say "Add: Sitepress.configuration.site = Sitepress::Site.new(root_path: '.')"
|
|
124
|
+
exit 1
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def setup_site_from_server!
|
|
129
|
+
# Store the site so RailsConfiguration can use it instead of creating a default.
|
|
130
|
+
# This must be set BEFORE requiring sitepress-rails.
|
|
131
|
+
if Sitepress.server.respond_to?(:site)
|
|
132
|
+
Sitepress.pending_site = Sitepress.server.site
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def initialize_rails_app!
|
|
137
|
+
require_relative "application"
|
|
138
|
+
|
|
139
|
+
Application.config.enable_site_error_reporting = false
|
|
140
|
+
Application.config.enable_site_reloading = false
|
|
141
|
+
|
|
142
|
+
Application.initialize!
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def compile_assets(output_path)
|
|
146
|
+
assets = Application.assets
|
|
147
|
+
|
|
148
|
+
if defined?(Propshaft) && assets.is_a?(Propshaft::Assembly)
|
|
149
|
+
FileUtils.mkdir_p(output_path)
|
|
150
|
+
processor = Propshaft::Processor.new(
|
|
151
|
+
load_path: assets.load_path,
|
|
152
|
+
output_path: output_path,
|
|
153
|
+
compilers: assets.compilers,
|
|
154
|
+
manifest_path: output_path.join(".manifest.json")
|
|
155
|
+
)
|
|
156
|
+
processor.process
|
|
157
|
+
elsif defined?(Sprockets) && assets.class.name.start_with?("Sprockets::")
|
|
158
|
+
FileUtils.mkdir_p(output_path)
|
|
159
|
+
manifest = Sprockets::Manifest.new(assets, output_path)
|
|
160
|
+
precompile = Application.config.assets.precompile
|
|
161
|
+
manifest.compile(precompile)
|
|
162
|
+
else
|
|
163
|
+
logger.warn "Unknown asset pipeline, skipping asset compilation"
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def logger
|
|
168
|
+
@logger ||= Logger.new(STDOUT).tap do |l|
|
|
169
|
+
l.formatter = ->(_, _, _, msg) { "#{msg}\n" }
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module Sitepress
|
|
2
|
+
# Plugin registry for CLI command extensions.
|
|
3
|
+
#
|
|
4
|
+
# Plugins are discovered via Bundler by looking for gems with
|
|
5
|
+
# `sitepress_plugin: "true"` in their gemspec metadata.
|
|
6
|
+
#
|
|
7
|
+
# Example plugin registration:
|
|
8
|
+
#
|
|
9
|
+
# Sitepress::Plugins.register(
|
|
10
|
+
# name: "deploy",
|
|
11
|
+
# cli: Sitepress::Deploy::CLI,
|
|
12
|
+
# description: "Deploy your site"
|
|
13
|
+
# )
|
|
14
|
+
#
|
|
15
|
+
module Plugins
|
|
16
|
+
class << self
|
|
17
|
+
def registry
|
|
18
|
+
@registry ||= {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Register a plugin CLI class.
|
|
22
|
+
#
|
|
23
|
+
# @param name [String] The subcommand name (e.g., "deploy")
|
|
24
|
+
# @param cli [Class] A Thor class with the plugin's commands
|
|
25
|
+
# @param description [String] Description shown in `sitepress help`
|
|
26
|
+
def register(name:, cli:, description: nil)
|
|
27
|
+
name = name.to_s
|
|
28
|
+
if registry.key?(name)
|
|
29
|
+
warn "WARNING: Sitepress plugin '#{name}' is already registered, skipping"
|
|
30
|
+
return
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
registry[name] = {
|
|
34
|
+
cli: cli,
|
|
35
|
+
description: description || "#{name} commands"
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Discover and load plugins from Bundler.
|
|
40
|
+
# Looks for gems with `sitepress_plugin: "true"` metadata.
|
|
41
|
+
def discover!
|
|
42
|
+
return unless defined?(Bundler)
|
|
43
|
+
|
|
44
|
+
Bundler.load.specs.each do |spec|
|
|
45
|
+
next unless spec.metadata["sitepress_plugin"] == "true"
|
|
46
|
+
|
|
47
|
+
begin
|
|
48
|
+
require spec.name
|
|
49
|
+
rescue LoadError => e
|
|
50
|
+
warn "WARNING: Could not load Sitepress plugin '#{spec.name}': #{e.message}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# List of registered plugin names.
|
|
56
|
+
def registered
|
|
57
|
+
registry.keys
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Get a specific plugin by name.
|
|
61
|
+
def get(name)
|
|
62
|
+
registry[name.to_s]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Iterate over all registered plugins.
|
|
66
|
+
def each(&block)
|
|
67
|
+
registry.each(&block)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Clear the registry (useful for testing).
|
|
71
|
+
def reset!
|
|
72
|
+
@registry = {}
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require "fileutils"
|
|
2
|
+
|
|
3
|
+
module Sitepress
|
|
4
|
+
# Creates new projects from a template.
|
|
5
|
+
class ProjectTemplate
|
|
6
|
+
DEFAULT_TEMPLATE = File.expand_path("../../../templates/default",__FILE__).freeze
|
|
7
|
+
|
|
8
|
+
include FileUtils
|
|
9
|
+
|
|
10
|
+
def initialize(path: DEFAULT_TEMPLATE)
|
|
11
|
+
@path = path
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def copy(to:)
|
|
15
|
+
cp_r @path, to
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require "irb"
|
|
2
|
+
|
|
3
|
+
module Sitepress
|
|
4
|
+
# Interactive REPL for Sitepress project
|
|
5
|
+
class REPL
|
|
6
|
+
attr_reader :site
|
|
7
|
+
|
|
8
|
+
def initialize(site:)
|
|
9
|
+
@site = site
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def start
|
|
13
|
+
ARGV.clear
|
|
14
|
+
IRB.setup(nil)
|
|
15
|
+
IRB.conf[:PROMPT_MODE] = :SIMPLE
|
|
16
|
+
workspace = IRB::WorkSpace.new(binding)
|
|
17
|
+
IRB::Irb.new(workspace).run(IRB.conf)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Provide convenient access in the REPL
|
|
21
|
+
def resources
|
|
22
|
+
site.resources
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def get(path)
|
|
26
|
+
site.get(path)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/sitepress.rb
CHANGED
|
@@ -1,2 +1,19 @@
|
|
|
1
|
+
require "sitepress-core"
|
|
2
|
+
require "sitepress-server"
|
|
3
|
+
|
|
1
4
|
module Sitepress
|
|
5
|
+
autoload :Application, "sitepress/application"
|
|
6
|
+
autoload :ApplicationServer, "sitepress/application_server"
|
|
7
|
+
autoload :CLI, "sitepress/cli"
|
|
8
|
+
autoload :Plugins, "sitepress/plugins"
|
|
9
|
+
autoload :ProjectTemplate, "sitepress/project_template"
|
|
10
|
+
autoload :REPL, "sitepress/repl"
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
# Server is only used in standalone mode
|
|
14
|
+
attr_accessor :server
|
|
15
|
+
|
|
16
|
+
# Used by CLI to pass site to RailsConfiguration before Rails is loaded
|
|
17
|
+
attr_accessor :pending_site
|
|
18
|
+
end
|
|
2
19
|
end
|
|
File without changes
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
class SiteController < ApplicationController
|
|
2
|
+
include Sitepress::SitePages
|
|
3
|
+
|
|
4
|
+
DEFAULT_SITE_LAYOUT = "layouts/layout".freeze
|
|
5
|
+
|
|
6
|
+
# This `rescue_from` order is important; it must come before the
|
|
7
|
+
# `include Sitepress::SitePages` statement; otherwise exceptions
|
|
8
|
+
# won't be properly handled.
|
|
9
|
+
rescue_from Exception, with: :standard_error
|
|
10
|
+
rescue_from ActionView::Template::Error, with: :action_view_template_error
|
|
11
|
+
rescue_from Sitepress::ParseError, with: :parse_error
|
|
12
|
+
rescue_from Sitepress::ResourceNotFoundError, with: :page_not_found
|
|
13
|
+
|
|
14
|
+
layout :site_layout
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
def site_layout
|
|
18
|
+
DEFAULT_SITE_LAYOUT if template_exists? DEFAULT_SITE_LAYOUT
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def standard_error(exception)
|
|
22
|
+
render_exception(template: "standard_error", exception: exception)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def action_view_template_error(exception)
|
|
26
|
+
render_exception(template: "action_template_error", exception: exception)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def parse_error(exception)
|
|
30
|
+
raise exception unless has_error_reporting_enabled?
|
|
31
|
+
|
|
32
|
+
@title = "Parse error"
|
|
33
|
+
@exception = exception
|
|
34
|
+
render "parse_error", layout: "sitepress_error", status: :internal_server_error, formats: :html
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def render_exception(template:, exception:)
|
|
38
|
+
raise exception unless has_error_reporting_enabled?
|
|
39
|
+
|
|
40
|
+
@title = "Error in resource #{current_page.asset.path}"
|
|
41
|
+
@exception = exception
|
|
42
|
+
render template, layout: "sitepress_error", status: :internal_server_error, formats: :html
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def page_not_found(exception)
|
|
46
|
+
raise exception unless has_error_reporting_enabled?
|
|
47
|
+
not_found
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def not_found
|
|
51
|
+
@title = "Could not find resource at #{request.path}"
|
|
52
|
+
render "not_found", layout: "sitepress_error", status: :not_found
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def has_error_reporting_enabled?
|
|
56
|
+
Sitepress::Application.config.enable_site_error_reporting
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def reload_site?
|
|
60
|
+
Sitepress::Application.config.enable_site_reloading
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module ApplicationHelper
|
|
2
|
+
DEFAULT_TITLE_KEY = "title".freeze
|
|
3
|
+
|
|
4
|
+
DEFAULT_ORDER_KEY = "order".freeze
|
|
5
|
+
|
|
6
|
+
# Links to a Sitepress::Resource. If the link does not have a block, the `title`
|
|
7
|
+
# attribute from Resource#data is used to create the text link.
|
|
8
|
+
def link_to_page(page, *args, title_key: DEFAULT_TITLE_KEY, **kwargs, &block)
|
|
9
|
+
if block_given?
|
|
10
|
+
link_to page.request_path, *args, **kwargs, &block
|
|
11
|
+
else
|
|
12
|
+
link_to page.data[DEFAULT_TITLE_KEY], page.request_path, *args, **kwargs
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Render a block within a layout. This is a useful, and prefered way, to handle
|
|
17
|
+
# nesting layouts, within Sitepress
|
|
18
|
+
def render_layout(layout, locals = {}, &block)
|
|
19
|
+
render inline: capture(&block), layout: "layouts/#{layout}", locals: locals
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Orders pages via the
|
|
23
|
+
def order_pages(pages, order_key: DEFAULT_ORDER_KEY)
|
|
24
|
+
pages.sort_by { |r| r.data.fetch(order_key, Float::INFINITY) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title><%= @title || "Sitepress" %></title>
|
|
7
|
+
<link href="/_sitepress/stylesheets/site.css" rel="stylesheet">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<header>
|
|
11
|
+
<img src="/_sitepress/images/logo.svg" alt="Sitepress" id="logo">
|
|
12
|
+
<h1 id="title"><%= @title || "Sitepress" %></h1>
|
|
13
|
+
</header>
|
|
14
|
+
<main>
|
|
15
|
+
<%= yield %>
|
|
16
|
+
</main>
|
|
17
|
+
<footer>
|
|
18
|
+
Sitepress <%= Sitepress::VERSION %> · <a href="https://sitepress.cc/">sitepress.cc</a>
|
|
19
|
+
</footer>
|
|
20
|
+
</body>
|
|
21
|
+
</html>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title><%= @title || "Sitepress" %></title>
|
|
7
|
+
<link href="/_sitepress/stylesheets/site.css" rel="stylesheet">
|
|
8
|
+
<script src="/_sitepress/javascripts/error.js" defer></script>
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div class="error-page">
|
|
12
|
+
<main class="error-main">
|
|
13
|
+
<div class="error-branding">
|
|
14
|
+
<img src="/_sitepress/images/logo.svg" alt="Sitepress" class="error-branding__logo">
|
|
15
|
+
<span class="error-branding__version">v<%= Sitepress::VERSION %></span>
|
|
16
|
+
</div>
|
|
17
|
+
<%= yield %>
|
|
18
|
+
</main>
|
|
19
|
+
</div>
|
|
20
|
+
</body>
|
|
21
|
+
</html>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<button class="copy-btn" onclick="copyError(this)">
|
|
2
|
+
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
3
|
+
<rect x="9" y="9" width="13" height="13" rx="2"></rect>
|
|
4
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
|
5
|
+
</svg>
|
|
6
|
+
Copy
|
|
7
|
+
</button>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<footer class="error-footer"><a href="https://sitepress.cc">sitepress.cc</a></footer>
|