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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/exe/sitepress +2 -1
  3. data/lib/sitepress/application.rb +61 -0
  4. data/lib/sitepress/application_server.rb +72 -0
  5. data/lib/sitepress/cli/plugin_helpers.rb +59 -0
  6. data/lib/sitepress/cli.rb +173 -0
  7. data/lib/sitepress/plugins.rb +76 -0
  8. data/lib/sitepress/project_template.rb +18 -0
  9. data/lib/sitepress/repl.rb +29 -0
  10. data/lib/sitepress.rb +17 -0
  11. data/rails/app/assets/config/manifest.js +0 -0
  12. data/rails/app/controllers/application_controller.rb +2 -0
  13. data/rails/app/controllers/site_controller.rb +62 -0
  14. data/rails/app/helpers/application_helper.rb +27 -0
  15. data/rails/app/views/layouts/sitepress.html.erb +21 -0
  16. data/rails/app/views/layouts/sitepress_error.html.erb +21 -0
  17. data/rails/app/views/site/_copy_button.html.erb +7 -0
  18. data/rails/app/views/site/_footer.html.erb +1 -0
  19. data/rails/app/views/site/_stack_trace.html.erb +48 -0
  20. data/rails/app/views/site/action_template_error.html.erb +48 -0
  21. data/rails/app/views/site/not_found.html.erb +39 -0
  22. data/rails/app/views/site/parse_error.html.erb +40 -0
  23. data/rails/app/views/site/standard_error.html.erb +30 -0
  24. data/rails/public/_sitepress/images/logo-dark.svg +13 -0
  25. data/rails/public/_sitepress/images/logo.svg +13 -0
  26. data/rails/public/_sitepress/javascripts/error.js +60 -0
  27. data/rails/public/_sitepress/stylesheets/site.css +464 -0
  28. data/sitepress.gemspec +11 -2
  29. data/templates/default/.gitignore +1 -0
  30. data/templates/default/Gemfile.tt +17 -0
  31. data/templates/default/README.md +75 -0
  32. data/templates/default/Rakefile +29 -0
  33. data/templates/default/assets/images/logo-brown.svg +13 -0
  34. data/templates/default/assets/images/logo-white.svg +13 -0
  35. data/templates/default/assets/javascripts/.gitkeep +0 -0
  36. data/templates/default/assets/stylesheets/site.css +86 -0
  37. data/templates/default/components/.gitkeep +0 -0
  38. data/templates/default/config/site.rb +10 -0
  39. data/templates/default/helpers/page_helper.rb +13 -0
  40. data/templates/default/layouts/layout.html.erb +22 -0
  41. data/templates/default/pages/favicon.ico +0 -0
  42. data/templates/default/pages/index.html.erb +18 -0
  43. metadata +86 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b707e7c86292a673b7ac37ea95e669fe9bcc089488526a0d2fce815052589c91
4
- data.tar.gz: 225126e120689d7a943698c7c6e0d5b221ebd8a7b669f53949f158239ad475e7
3
+ metadata.gz: 30daa89481221dd83d4fc8041ff73e5187ea0715ca763a0d6542899fadb0f60b
4
+ data.tar.gz: 04d1a39f9d91d1ae2b492e2619ade8a1217395948dc66d663c8af196b2aa0ce0
5
5
  SHA512:
6
- metadata.gz: 282751df85cd68d7d160bb2266e270dc75b3740d8d45c14ab7a4a2330687ca5244a395aa2fdbbb6a274d20f996e18415160c87836f4e220b963fe06c36c69a7d
7
- data.tar.gz: e0365ccfcc30ee2ab4fb5542c4785edb8d48bb7438f22e1ac11da95ed5043372d39fc568bde28beb7840bfba6df7bebd09208ae3ec060584f06794cce1b72f9a
6
+ metadata.gz: 1008b2d97905b6749180bf8c79b85987ffd20c219e0dc9cdbb657b2103a42ff473ea59f8bc23dd93f537b076515bd02c9291b42977b816c86f662130b273fc4c
7
+ data.tar.gz: d4a8406386ea5a29107c6bcadc451f094ccae768565881dca68695cb26115b938c057a469ba2caac63f9df55ee5631a1b6476447961e78158d6771b738c4d229
data/exe/sitepress CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "sitepress-cli"
3
+ require "sitepress"
4
+ require "sitepress/cli"
4
5
 
5
6
  Sitepress::CLI.start(ARGV)
@@ -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,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -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 %> &middot; <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>