sitepress-server 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab3c5cace9a02fd8a339efde272da19d43992942a5499ab159a28da7d2620189
4
- data.tar.gz: ad7038cf85d66df7295bbcf1e2c7a3314b74966f04b5cc51237e31ac55f8167a
3
+ metadata.gz: da4071703d528ea6fe2a3c53eb05014ad67bd91a32b119c67279e75b6a995804
4
+ data.tar.gz: de43f44a390779fdf934e336d9a6d975bf43c4f6486bd0ba9350662cd0b7d409
5
5
  SHA512:
6
- metadata.gz: a3aa3f90831111789214e63e0d78066c8f3328cfec348998a561bd2ef3f3237cd455e9de361480a3b32ca3d46d5e87902342ad67147d05dc29669a4020199989
7
- data.tar.gz: a11888b1556f8d57cd8c55d4154c2ea2a84310a80f335adcb13f642d9d53f128ae5e8be9518de405a8d00b034710d8cfa300eb7107b5dfbb960e5e20a439fda8
6
+ metadata.gz: 88cecc2bcdd9566b56c0e1ef960580b41546e35f0afd7bd0be71a560277d03adb47f2527c55699a75c9d93821cf0fbc264e43d50b40645ccc7bab9cca28a0ca7
7
+ data.tar.gz: 30201abb12ead0ffc1e15f536cf2d5ca20fe4b7e566f41c7ecbe21776da2fa30094440931a5057adef8e2ee2a748102df996a021517179da2125fccfe3b685f4
@@ -0,0 +1,32 @@
1
+ module Sitepress
2
+ # Represents a labeled shell command that runs as part of the development server.
3
+ # Used for things like Tailwind CSS watchers, esbuild, etc.
4
+ class Process
5
+ COLORS = [:red, :green, :yellow, :blue, :magenta, :cyan].freeze
6
+
7
+ attr_reader :label, :command
8
+ attr_accessor :color
9
+
10
+ def initialize(label:, command:)
11
+ @label = label.to_sym
12
+ @command = command
13
+ @color = nil
14
+ @pid = nil
15
+ end
16
+
17
+ # Run the process, yielding each line of output.
18
+ # This blocks until the process exits.
19
+ def run(&block)
20
+ IO.popen(command, err: [:child, :out]) do |io|
21
+ io.each_line do |line|
22
+ yield line.chomp if block_given?
23
+ end
24
+ end
25
+ end
26
+
27
+ # Assign a color based on index (for supervisor to assign unique colors)
28
+ def self.color_for_index(index)
29
+ COLORS[index % COLORS.length]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,66 @@
1
+ require "async"
2
+
3
+ module Sitepress
4
+ # Runs multiple processes concurrently, with colored and labeled output.
5
+ class ProcessSupervisor
6
+ ANSI_COLORS = {
7
+ red: "\e[31m",
8
+ green: "\e[32m",
9
+ yellow: "\e[33m",
10
+ blue: "\e[34m",
11
+ magenta: "\e[35m",
12
+ cyan: "\e[36m",
13
+ reset: "\e[0m"
14
+ }.freeze
15
+
16
+ attr_reader :processes
17
+
18
+ def initialize
19
+ @processes = []
20
+ @mutex = Mutex.new
21
+ end
22
+
23
+ def add(process)
24
+ process.color = Process.color_for_index(@processes.size)
25
+ @processes << process
26
+ end
27
+
28
+ # Run all processes concurrently using Async.
29
+ # This method blocks until all processes exit.
30
+ def run
31
+ return if @processes.empty?
32
+
33
+ Sync do |task|
34
+ @processes.each do |process|
35
+ task.async do
36
+ run_process(process)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def run_process(process)
45
+ process.run do |line|
46
+ output(process, line)
47
+ end
48
+ rescue => e
49
+ output(process, "Error: #{e.message}")
50
+ end
51
+
52
+ def output(process, line)
53
+ color = ANSI_COLORS[process.color] || ""
54
+ reset = ANSI_COLORS[:reset]
55
+ label = process.label.to_s.ljust(max_label_length)
56
+
57
+ @mutex.synchronize do
58
+ puts "#{color}[#{label}]#{reset} #{line}"
59
+ end
60
+ end
61
+
62
+ def max_label_length
63
+ @max_label_length ||= @processes.map { |p| p.label.to_s.length }.max || 0
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,159 @@
1
+ require "listen"
2
+
3
+ module Sitepress
4
+ # Manages browser reloading: SSE client connections and file watching.
5
+ class Reloader
6
+ attr_reader :watch_paths
7
+ attr_accessor :logger
8
+
9
+ def initialize(logger: nil)
10
+ @clients = {}
11
+ @next_client_id = 0
12
+ @watch_paths = []
13
+ @listener = nil
14
+ @logger = logger
15
+ end
16
+
17
+ # Add a path to watch for changes.
18
+ def watch(path)
19
+ @watch_paths << path.to_s
20
+ end
21
+
22
+ # Create an SSE connection for a client.
23
+ # Returns a Rack response tuple.
24
+ def connect
25
+ client_id = @next_client_id += 1
26
+ body = SSEConnection.new(client_id, @clients)
27
+ [200, sse_headers, body]
28
+ end
29
+
30
+ # Notify all connected clients to reload.
31
+ def notify(modified: [], added: [], removed: [])
32
+ log "Files changed at #{Time.now}"
33
+ modified.each { |f| log " Modified #{f}" }
34
+ added.each { |f| log " Added #{f}" }
35
+ removed.each { |f| log " Removed #{f}" }
36
+ log "Reloading #{@clients.size} client(s)"
37
+ log ""
38
+ log ""
39
+
40
+ @clients.each_value do |queue|
41
+ queue << "event: change\ndata: \n\n" rescue nil
42
+ end
43
+ end
44
+
45
+ # Start watching files for changes.
46
+ # Call this within an Async task.
47
+ def start_watching
48
+ paths = @watch_paths.select { |p| File.directory?(p) }
49
+ return if paths.empty?
50
+
51
+ log "Reloader watching"
52
+
53
+ @listener = Listen.to(*paths) do |modified, added, removed|
54
+ notify(modified: modified, added: added, removed: removed)
55
+ end
56
+
57
+ @listener.start
58
+ sleep # Keep the task alive
59
+ end
60
+
61
+ # Stop watching files.
62
+ def stop_watching
63
+ @listener&.stop
64
+ end
65
+
66
+ # Returns a Rack middleware that injects the reload script.
67
+ def middleware
68
+ Middleware
69
+ end
70
+
71
+ private
72
+
73
+ def log(message)
74
+ @logger&.puts message
75
+ end
76
+
77
+ def sse_headers
78
+ {
79
+ "Content-Type" => "text/event-stream",
80
+ "Cache-Control" => "no-cache"
81
+ }
82
+ end
83
+
84
+ # SSE response body that yields messages from a queue.
85
+ class SSEConnection
86
+ def initialize(client_id, clients)
87
+ @client_id = client_id
88
+ @clients = clients
89
+ @queue = Queue.new
90
+ end
91
+
92
+ def each
93
+ @clients[@client_id] = @queue
94
+ yield "data: connected\n\n"
95
+
96
+ loop do
97
+ msg = @queue.pop
98
+ break if msg == :close
99
+ yield msg
100
+ end
101
+ rescue Errno::EPIPE, IOError
102
+ # Client disconnected
103
+ ensure
104
+ @clients.delete(@client_id)
105
+ end
106
+
107
+ def close
108
+ @queue << :close rescue nil
109
+ end
110
+ end
111
+
112
+ # Rack middleware that injects reload script into HTML responses.
113
+ class Middleware
114
+ SCRIPT = <<~HTML
115
+ <script>
116
+ (function() {
117
+ var es = new EventSource("/_sitepress/changes");
118
+ es.addEventListener("change", function() { location.reload(); });
119
+ })();
120
+ </script>
121
+ HTML
122
+
123
+ def initialize(app)
124
+ @app = app
125
+ end
126
+
127
+ def call(env)
128
+ status, headers, body = @app.call(env)
129
+
130
+ if html_response?(headers)
131
+ body = inject_script(body)
132
+ end
133
+
134
+ [status, headers, body]
135
+ end
136
+
137
+ private
138
+
139
+ def html_response?(headers)
140
+ content_type = headers["Content-Type"] || headers["content-type"] || ""
141
+ content_type.include?("text/html")
142
+ end
143
+
144
+ def inject_script(body)
145
+ html = +""
146
+ body.each { |chunk| html << chunk }
147
+ body.close if body.respond_to?(:close)
148
+
149
+ if html.include?("</body>")
150
+ html.sub!("</body>", "#{SCRIPT}</body>")
151
+ else
152
+ html << SCRIPT
153
+ end
154
+
155
+ [html]
156
+ end
157
+ end
158
+ end
159
+ end
@@ -1,60 +1,111 @@
1
- require "action_controller/railtie"
2
- require "propshaft"
3
- require "sitepress-rails"
1
+ require "async"
2
+ require "async/http/endpoint"
3
+ require "console"
4
+ require "falcon"
5
+ require "protocol/rack/adapter"
4
6
 
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.
10
7
  module Sitepress
11
- class Server < Rails::Application
12
- # Control whether or not to display friendly error reporting messages
13
- # in Sitepress. The development server turns this on an handles exception,
14
- # while the compile and other environments would likely have this disabled.
15
- config.enable_site_error_reporting = false
16
-
17
- # When in a development environment, we'll want to reload the site between
18
- # requests so we can see the latest changes; otherwise, load the site once
19
- # and we're done.
20
- config.enable_site_reloading = false
21
-
22
- # Default to a development environment type of configuration, which would reload the site.
23
- # This gets reset later depending on a preference in the `before_initialize` callback.
24
- config.eager_load = true
25
- config.cache_classes = true
26
-
27
- config.before_initialize do
28
- # Eager load classes, content, etc. to boost performance when site reloading is disabled.
29
- config.eager_load = !config.enable_site_reloading
30
-
31
- # Cache classes for speed in production environments when site reloading is disabled.
32
- config.cache_classes = !config.enable_site_reloading
33
- end
34
-
35
- # Path that points the the Sitepress UI rails app; which displays routes, error messages.
36
- # etc. to the user if `enable_site_error_reporting` is enabled.
37
- config.root = File.join(File.dirname(__FILE__), "../../rails")
38
-
39
- # Rails won't start without this.
40
- config.secret_key_base = SecureRandom.uuid
41
-
42
- # Setup routes. The `constraints` key is set to `nil` so the `SiteController` can
43
- # treat a page not being found as an exception, which it then handles. If the constraint
44
- # was set to the default, Sitepress would hand off routing back to rails if something isn't
45
- # found and fail silently.
46
- routes.append { sitepress_pages root: true, controller: "site", constraints: nil }
47
-
48
- # Setup logger.
49
- logger = ActiveSupport::Logger.new(STDOUT)
50
- logger.formatter = config.log_formatter
51
- config.logger = ActiveSupport::TaggedLogging.new(logger)
52
-
53
- # Allow any host to connect to the development server. The actual binding is
54
- # controlled by server in the `sitepress-cli`; not by Rails.
55
- config.hosts << proc { true } if config.respond_to? :hosts
56
-
57
- # Stand-alone boot locations
58
- paths["config/initializers"] << File.expand_path("./config/initializers")
8
+ # Development server using Falcon with process supervision and optional reloading.
9
+ #
10
+ # Example:
11
+ # app = MyRackApp.new
12
+ # reloader = Sitepress::Reloader.new
13
+ # reloader.watch "./pages"
14
+ # server = Sitepress::Server.new(app, reloader: reloader)
15
+ # server.add_process :css, "tailwindcss -w -i ./assets/site.css -o ./public/site.css"
16
+ # server.run
17
+ #
18
+ class Server
19
+ DEFAULT_HOST = "127.0.0.1".freeze
20
+ DEFAULT_PORT = 8080
21
+
22
+ attr_reader :app, :processes, :reloader
23
+ attr_accessor :host, :port
24
+
25
+ def initialize(app, reloader: nil)
26
+ @app = app
27
+ @processes = []
28
+ @reloader = reloader
29
+ @host = DEFAULT_HOST
30
+ @port = DEFAULT_PORT
31
+ end
32
+
33
+ # Add a labeled process to run alongside the server.
34
+ def add_process(label, command)
35
+ process = Process.new(label: label, command: command)
36
+ @processes << process
37
+ process
38
+ end
39
+
40
+ # Start the server and all configured processes.
41
+ def run
42
+ print_banner
43
+
44
+ Sync do |task|
45
+ start_processes(task)
46
+ start_reloader(task)
47
+ start_falcon
48
+ end
49
+ rescue Interrupt
50
+ puts "\nShutting down..."
51
+ end
52
+
53
+ private
54
+
55
+ def print_banner
56
+ # Suppress noisy EPIPE warnings when SSE clients disconnect during navigation
57
+ ::Console.logger.level = :error if reloader
58
+
59
+ puts "Sitepress server starting..."
60
+ puts " URL: http://#{host}:#{port}/"
61
+ puts " Reloader: #{reloader ? 'enabled' : 'disabled'}"
62
+ puts ""
63
+ end
64
+
65
+ def start_processes(task)
66
+ return if @processes.empty?
67
+
68
+ task.async do
69
+ supervisor = ProcessSupervisor.new
70
+ @processes.each { |p| supervisor.add(p) }
71
+ supervisor.run
72
+ end
73
+ end
74
+
75
+ def start_reloader(task)
76
+ return unless reloader
77
+
78
+ task.async { reloader.start_watching }
79
+ end
80
+
81
+ def start_falcon
82
+ rack_app = build_rack_app
83
+ adapted_app = Protocol::Rack::Adapter.new(rack_app)
84
+ endpoint = Async::HTTP::Endpoint.parse("http://#{host}:#{port}/")
85
+
86
+ server = Falcon::Server.new(adapted_app, endpoint)
87
+ server.run.wait
88
+ end
89
+
90
+ def build_rack_app
91
+ main_app = app
92
+ r = reloader
93
+
94
+ Rack::Builder.new do
95
+ if r
96
+ use r.middleware
97
+
98
+ map "/_sitepress/changes" do
99
+ run ->(env) { r.connect }
100
+ end
101
+ end
102
+
103
+ map "/_sitepress/source" do
104
+ run SourceViewer.new
105
+ end
106
+
107
+ run main_app
108
+ end
109
+ end
59
110
  end
60
111
  end
@@ -0,0 +1,85 @@
1
+ require "json"
2
+
3
+ module Sitepress
4
+ class SourceViewer
5
+ CONTEXT_LINES = 5
6
+
7
+ def call(env)
8
+ return method_not_allowed unless env["REQUEST_METHOD"] == "GET"
9
+
10
+ params = Rack::Utils.parse_query(env["QUERY_STRING"])
11
+ file = params["file"]
12
+ line = params["line"].to_i
13
+
14
+ return bad_request("Missing file parameter") unless file
15
+ return bad_request("Missing line parameter") unless line > 0
16
+ return not_found("File not found") unless File.exist?(file)
17
+ return forbidden("Access denied") unless allowed_path?(file)
18
+
19
+ source = read_source(file, line)
20
+ json_response(source)
21
+ rescue => e
22
+ error_response(e.message)
23
+ end
24
+
25
+ private
26
+
27
+ def read_source(file, target_line)
28
+ lines = File.readlines(file)
29
+ start_line = [target_line - CONTEXT_LINES, 1].max
30
+ end_line = [target_line + CONTEXT_LINES, lines.length].min
31
+
32
+ source_lines = (start_line..end_line).map do |num|
33
+ {
34
+ number: num,
35
+ code: lines[num - 1]&.chomp || "",
36
+ error: num == target_line
37
+ }
38
+ end
39
+
40
+ {
41
+ file: file,
42
+ line: target_line,
43
+ lines: source_lines
44
+ }
45
+ end
46
+
47
+ def allowed_path?(file)
48
+ expanded = File.expand_path(file)
49
+
50
+ # Only allow .rb and .erb files (source code)
51
+ return false unless expanded.end_with?('.rb', '.erb', '.html.erb')
52
+
53
+ # Block access to sensitive paths
54
+ sensitive = %w[/etc /var /private /root]
55
+ return false if sensitive.any? { |s| expanded.start_with?(s) }
56
+
57
+ # Allow any readable source file in development
58
+ File.readable?(expanded)
59
+ end
60
+
61
+ def json_response(data)
62
+ [200, { "Content-Type" => "application/json" }, [JSON.generate(data)]]
63
+ end
64
+
65
+ def bad_request(message)
66
+ [400, { "Content-Type" => "application/json" }, [JSON.generate({ error: message })]]
67
+ end
68
+
69
+ def not_found(message)
70
+ [404, { "Content-Type" => "application/json" }, [JSON.generate({ error: message })]]
71
+ end
72
+
73
+ def forbidden(message)
74
+ [403, { "Content-Type" => "application/json" }, [JSON.generate({ error: message })]]
75
+ end
76
+
77
+ def method_not_allowed
78
+ [405, { "Content-Type" => "application/json" }, [JSON.generate({ error: "Method not allowed" })]]
79
+ end
80
+
81
+ def error_response(message)
82
+ [500, { "Content-Type" => "application/json" }, [JSON.generate({ error: message })]]
83
+ end
84
+ end
85
+ end
@@ -1,5 +1,7 @@
1
- require "sitepress-core"
2
-
3
1
  module Sitepress
4
- autoload :Server, "sitepress/server"
2
+ autoload :Process, "sitepress/process"
3
+ autoload :ProcessSupervisor, "sitepress/process_supervisor"
4
+ autoload :Reloader, "sitepress/reloader"
5
+ autoload :Server, "sitepress/server"
6
+ autoload :SourceViewer, "sitepress/source_viewer"
5
7
  end
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Brad Gessler"]
10
10
  spec.email = ["bradgessler@gmail.com"]
11
11
  spec.licenses = ["MIT"]
12
- spec.summary = %q{Sitepress rack app for stand-alone of embedded usage.}
12
+ spec.summary = %q{Falcon-based development server for Sitepress with process supervision and live reload.}
13
13
  spec.homepage = "https://sitepress.cc/"
14
14
 
15
15
  spec.metadata["homepage_uri"] = spec.homepage
@@ -17,11 +17,13 @@ Gem::Specification.new do |spec|
17
17
  spec.metadata["changelog_uri"] = "https://github.com/sitepress/sitepress/tags"
18
18
 
19
19
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
- spec.bindir = "exe"
21
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
20
  spec.require_paths = ["lib"]
23
21
 
24
- spec.add_development_dependency "rack-test"
22
+ # Falcon web server
23
+ spec.add_runtime_dependency "falcon", ">= 0.47"
24
+ spec.add_runtime_dependency "async", ">= 2.0"
25
+ spec.add_runtime_dependency "async-http", ">= 0.60"
25
26
 
26
- spec.add_runtime_dependency "sitepress-rails", spec.version
27
+ # File watching for live reload
28
+ spec.add_runtime_dependency "listen", ">= 3.0"
27
29
  end
metadata CHANGED
@@ -1,42 +1,70 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sitepress-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.beta1
4
+ version: 5.0.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brad Gessler
8
- bindir: exe
8
+ bindir: bin
9
9
  cert_chain: []
10
- date: 2026-02-20 00:00:00.000000000 Z
10
+ date: 2026-03-06 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: rack-test
13
+ name: falcon
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '0'
19
- type: :development
18
+ version: '0.47'
19
+ type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '0'
25
+ version: '0.47'
26
26
  - !ruby/object:Gem::Dependency
27
- name: sitepress-rails
27
+ name: async
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - '='
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: async-http
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
31
45
  - !ruby/object:Gem::Version
32
- version: 5.0.0.beta1
46
+ version: '0.60'
33
47
  type: :runtime
34
48
  prerelease: false
35
49
  version_requirements: !ruby/object:Gem::Requirement
36
50
  requirements:
37
- - - '='
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0.60'
54
+ - !ruby/object:Gem::Dependency
55
+ name: listen
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
38
66
  - !ruby/object:Gem::Version
39
- version: 5.0.0.beta1
67
+ version: '3.0'
40
68
  email:
41
69
  - bradgessler@gmail.com
42
70
  executables: []
@@ -44,18 +72,11 @@ extensions: []
44
72
  extra_rdoc_files: []
45
73
  files:
46
74
  - lib/sitepress-server.rb
75
+ - lib/sitepress/process.rb
76
+ - lib/sitepress/process_supervisor.rb
77
+ - lib/sitepress/reloader.rb
47
78
  - lib/sitepress/server.rb
48
- - rails/app/assets/config/manifest.js
49
- - rails/app/controllers/application_controller.rb
50
- - rails/app/controllers/site_controller.rb
51
- - rails/app/helpers/application_helper.rb
52
- - rails/app/views/layouts/sitepress.html.erb
53
- - rails/app/views/site/action_template_error.html.erb
54
- - rails/app/views/site/not_found.html.erb
55
- - rails/app/views/site/parse_error.html.erb
56
- - rails/app/views/site/standard_error.html.erb
57
- - rails/public/_sitepress/images/logo.svg
58
- - rails/public/_sitepress/stylesheets/site.css
79
+ - lib/sitepress/source_viewer.rb
59
80
  - sitepress-server.gemspec
60
81
  homepage: https://sitepress.cc/
61
82
  licenses:
@@ -80,5 +101,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
101
  requirements: []
81
102
  rubygems_version: 3.6.2
82
103
  specification_version: 4
83
- summary: Sitepress rack app for stand-alone of embedded usage.
104
+ summary: Falcon-based development server for Sitepress with process supervision and
105
+ live reload.
84
106
  test_files: []
File without changes
@@ -1,2 +0,0 @@
1
- class ApplicationController < ActionController::Base
2
- end
@@ -1,62 +0,0 @@
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", 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", 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", status: :not_found
53
- end
54
-
55
- def has_error_reporting_enabled?
56
- Sitepress::Server.config.enable_site_error_reporting
57
- end
58
-
59
- def reload_site?
60
- Sitepress::Server.config.enable_site_reloading
61
- end
62
- end
@@ -1,26 +0,0 @@
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
- end
@@ -1,20 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset='utf-8'>
5
- <title><%= @title || "Sitepress" %></title>
6
- <link href='/_sitepress/stylesheets/site.css' rel='stylesheet' type='text/css'>
7
- </head>
8
- <body>
9
- <header>
10
- <img src='/_sitepress/images/logo.svg' id='logo'>
11
- <h1 id="title"><%= @title || "Sitepress" %></h1>
12
- </header>
13
- <main>
14
- <%= yield %>
15
- </main>
16
- </body>
17
- <footer>
18
- Running version Sitepress <%= Sitepress::VERSION %>. Visit <a href="https://sitepress.cc/">sitepress.cc</a> for documentation, help, and updates.
19
- </footer>
20
- </html>
@@ -1,74 +0,0 @@
1
- <% body_offset = current_page.asset.respond_to?(:body_line_offset) ? current_page.asset.body_line_offset : 1 %>
2
- <% adjusted_line = @exception.line_number.to_i + body_offset - 1 %>
3
- <% plain_text_error = <<~ERROR
4
- #{@exception.class}: #{@exception.message}
5
- File: #{current_page.asset.path}:#{adjusted_line}
6
-
7
- Source:
8
- #{@exception.annotated_source_code.join("\n")}
9
-
10
- Backtrace:
11
- #{@exception.backtrace.first(15).join("\n")}
12
- ERROR
13
- %>
14
-
15
- <button onclick="navigator.clipboard.writeText(document.getElementById('error-text').textContent).then(() => this.textContent = 'Copied!').catch(() => this.textContent = 'Failed')" style="float: right; padding: 8px 16px; cursor: pointer; background: transparent; border: 1px solid rgba(255,255,255,0.3); color: inherit; border-radius: 4px; font-size: 14px; transition: all 0.2s ease;" onmouseover="this.style.background='rgba(255,255,255,0.1)'; this.style.borderColor='rgba(255,255,255,0.5)'" onmouseout="this.style.background='transparent'; this.style.borderColor='rgba(255,255,255,0.3)'">Copy Error</button>
16
- <pre id="error-text" style="display: none;"><%= plain_text_error %></pre>
17
-
18
- <h2><%= @exception.class %>: <%= @exception.message %> in <%= current_page.asset.path %>:<%= adjusted_line %></h2>
19
- <h3>Source</h3>
20
-
21
- <code>
22
- <pre><%= current_page.asset.path %>:<%= adjusted_line %>
23
- <%= @exception.annotated_source_code.join("\n") %></pre>
24
- </code>
25
-
26
- <%
27
- # Clean up ugly ERB-generated method names in stack traces
28
- clean_trace = ->(line) {
29
- if line =~ /\.erb:\d+:in '___/
30
- line.sub(/:in '___.*'$/, '')
31
- else
32
- line
33
- end
34
- }
35
- app_trace = @exception.backtrace.reject { |line| line.include?('/gems/') || line.include?('/ruby/') }.map(&clean_trace)
36
- framework_trace = @exception.backtrace.select { |line| line.include?('/gems/') || line.include?('/ruby/') }.map(&clean_trace)
37
- %>
38
-
39
- <h3>Backtrace</h3>
40
- <code>
41
- <pre style="margin: 0;"><%= app_trace.first(10).join("\n") %></pre>
42
- <% if framework_trace.any? %>
43
- <details style="margin-top: 1em;">
44
- <summary style="cursor: pointer; font-size: 0.85em; padding: 0.5em 0; border-top: 1px solid rgba(255,255,255,0.15); user-select: none; display: flex; align-items: center; gap: 0.5em; opacity: 0.7;">
45
- <span style="display: inline-block; transition: transform 0.2s ease;">▶</span>
46
- Framework Trace (<%= framework_trace.length %> lines)
47
- </summary>
48
- <pre style="margin: 0.5em 0 0 0;"><%= framework_trace.join("\n") %></pre>
49
- </details>
50
- <% end %>
51
- </code>
52
- <style>
53
- details[open] summary span { transform: rotate(90deg) !important; }
54
- details summary::-webkit-details-marker { display: none; }
55
- details summary::marker { display: none; }
56
- </style>
57
-
58
- <h3>Resources</h3>
59
- <table>
60
- <thead>
61
- <th>Request path</th>
62
- <th>Asset path</th>
63
- <th>Media type</th>
64
- </thead>
65
- <tbody>
66
- <% site.resources.each do |resource| %>
67
- <tr>
68
- <td><%= link_to resource.request_path, resource.request_path %></td>
69
- <td><%= resource.asset.path %></td>
70
- <td><%= resource.asset.mime_type %></td>
71
- </tr>
72
- <% end %>
73
- </tbody>
74
- </table>
@@ -1,17 +0,0 @@
1
- <h2>Available resources</h2>
2
- <table>
3
- <thead>
4
- <th>Request path</th>
5
- <th>Asset path</th>
6
- <th>Mime type</th>
7
- </thead>
8
- <tbody>
9
- <% site.resources.each do |resource| %>
10
- <tr>
11
- <td><%= link_to resource.request_path, resource.request_path %></td>
12
- <td><%= resource.asset.path %></td>
13
- <td><%= resource.asset.mime_type %></td>
14
- </tr>
15
- <% end %>
16
- </tbody>
17
- </table>
@@ -1,35 +0,0 @@
1
- <h2><%= @exception.class %></h2>
2
- <h3><%= @exception.message %></h3>
3
-
4
- <p>This error typically occurs when there's invalid YAML in the frontmatter of a page.</p>
5
-
6
- <h3>Common causes</h3>
7
- <ul>
8
- <li>Missing closing <code>---</code> delimiter</li>
9
- <li>Invalid YAML syntax (bad indentation, missing quotes around special characters)</li>
10
- <li>Tabs instead of spaces for indentation</li>
11
- <li>Special characters that need quoting: <code>: { } [ ] , &amp; * # ? | - &lt; &gt; = ! % @ \</code></li>
12
- </ul>
13
-
14
- <h3>Backtrace</h3>
15
- <code>
16
- <pre><%= @exception.backtrace.join("\n") %></pre>
17
- </code>
18
-
19
- <h3>Resources</h3>
20
- <table>
21
- <thead>
22
- <th>Request path</th>
23
- <th>Asset path</th>
24
- <th>Media type</th>
25
- </thead>
26
- <tbody>
27
- <% site.resources.each do |resource| %>
28
- <tr>
29
- <td><%= link_to resource.request_path, resource.request_path %></td>
30
- <td><%= resource.asset.path %></td>
31
- <td><%= resource.asset.mime_type %></td>
32
- </tr>
33
- <% end %>
34
- </tbody>
35
- </table>
@@ -1,29 +0,0 @@
1
- <h2><%= @exception.class %>: <%= @exception.message %> in <%= current_page.asset.path %></h2>
2
- <h3>Source</h3>
3
-
4
- <code>
5
- <pre><%= current_page.asset.path %></pre>
6
- </code>
7
-
8
- <h3>Backtrace</h3>
9
- <code>
10
- <pre><%= @exception.backtrace.join("\n") %></pre>
11
- </code>
12
-
13
- <h3>Resources</h3>
14
- <table>
15
- <thead>
16
- <th>Request path</th>
17
- <th>Asset path</th>
18
- <th>Media type</th>
19
- </thead>
20
- <tbody>
21
- <% site.resources.each do |resource| %>
22
- <tr>
23
- <td><%= link_to resource.request_path, resource.request_path %></td>
24
- <td><%= resource.asset.path %></td>
25
- <td><%= resource.asset.mime_type %></td>
26
- </tr>
27
- <% end %>
28
- </tbody>
29
- </table>
@@ -1,13 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg width="895px" height="895px" viewBox="0 0 895 895" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
- <title>Sitepress logo</title>
4
- <desc>A static and dynamic website builder</desc>
5
- <defs></defs>
6
- <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
7
- <g id="logo" fill="#ffffff">
8
- <path d="M334.72,537.93 C325.82,530.6 313.41,526.88 297.83,526.88 L254.05,526.88 L254.05,618.4 L297.84,618.4 C313.41,618.4 325.84,614.63 334.72,607.2 C343.6,599.77 348.01,588.2 348.01,572.49 C348.01,556.78 343.54,545.2 334.72,537.93 L334.72,537.93 Z" id="Shape"></path>
9
- <path d="M859.29,274.59 C770.211759,62.9463102 535.248488,-46.7589164 315.795351,20.8303235 C96.3422149,88.4195635 -36.1856795,311.308174 9.24445457,536.395018 C54.6745886,761.481862 263.278739,915.518494 491.767697,892.697877 C720.256655,869.87726 894.274848,677.625748 894.29,448 C894.373576,388.434111 882.470683,329.460375 859.29,274.59 L859.29,274.59 Z M573.53,155.3 C573.53,150.7 576.17,148.06 580.77,148.06 L684.32,148.06 C688.73,148.06 691.27,150.59 691.27,155.01 C691.27,159.79 688.74,162.54 684.32,162.54 L588,162.54 L588,249 L632.54,249 C636.95,249 639.48,251.74 639.48,256.53 C639.48,260.94 636.95,263.48 632.54,263.48 L588,263.48 L588,350.23 L684.32,350.23 C688.73,350.23 691.27,352.97 691.27,357.76 C691.27,362.17 688.74,364.71 684.32,364.71 L580.77,364.71 C576.17,364.71 573.53,362.07 573.53,357.47 L573.53,155.3 Z M401.53,89.3 C402.779293,87.9227726 404.571684,87.1655789 406.43,87.23 L553.75,87.23 C558.27,87.23 560.53,89.3666667 560.53,93.64 C560.53,98.4133333 558.27,100.8 553.75,100.8 L487.06,100.8 L487.06,355.91 C487.06,360.43 484.8,362.69 480.28,362.69 C475.76,362.69 473.5,360.43 473.5,355.91 L473.5,100.83 L406.43,100.83 C404.571176,100.897181 402.777669,100.139516 401.53,98.76 C399.018254,96.1222984 399.018254,91.9777016 401.53,89.34 L401.53,89.3 Z M361.08,93.63 C361.08,89.3633333 363.34,87.2266667 367.86,87.22 C372.38,87.2133333 374.64,89.35 374.64,93.63 L374.64,355.91 C374.64,360.43 372.38,362.69 367.86,362.69 C363.34,362.69 361.08,360.43 361.08,355.91 L361.08,93.63 Z M208.57,329.63 C210.15,327.79 211.7,326.89 213.29,326.89 C214.88,326.89 216.79,328.24 219.49,331.55 C221.62,334.16 224.09,337.02 226.84,340.05 C229.42,342.91 233.97,345.62 240.34,348.11 C247.586888,350.800137 255.270834,352.119225 263,352 C278.29,352 290,348.13 297.82,340.5 C305.64,332.87 309.58,321.57 309.58,306.88 C309.58,297.17 307.85,288.88 304.43,282.35 C301.410563,276.249269 296.784618,271.087433 291.05,267.42 C285.097567,263.784066 278.78788,260.768283 272.22,258.42 L251.58,251.15 C244.726443,248.889218 238.156396,245.84579 232,242.08 C225.705868,238.108684 220.588935,232.525633 217.18,225.91 C213.45,218.97 211.56,210.38 211.56,200.39 C211.56,190.23 213.44,181.39 217.16,174.03 C220.484889,167.084479 225.841413,161.312965 232.52,157.48 C238.378086,154.162981 244.677689,151.694992 251.23,150.15 C257.679927,148.734499 264.266659,148.036922 270.87,148.07 C281.863142,147.943398 292.800246,149.653588 303.23,153.13 C313.87,156.83 318.83,160.66 318.83,165.2 C318.754645,167.219913 317.98465,169.151963 316.65,170.67 C315.09,172.62 313.39,173.6 311.6,173.6 C310.78,173.6 309.49,173.37 304.51,170.6 C300.133975,168.352176 295.540237,166.556229 290.8,165.24 C284.225834,163.369844 277.414361,162.467037 270.58,162.56 C263.351008,162.469822 256.146813,163.422972 249.19,165.39 C243.12,167.2 237.67,171.04 233.01,176.8 C228.35,182.56 226.01,190.16 226.01,199.54 C226.01,207.46 227.72,214.2 231.09,219.54 C234.303387,224.772292 238.912858,229.004278 244.4,231.76 C250.482431,234.769407 256.763789,237.358797 263.2,239.51 C270.06,241.83 277.09,244.44 284.1,247.26 C291.011648,250.019216 297.587203,253.555254 303.7,257.8 C309.78,262.06 314.76,268.35 318.48,276.5 C322.2,284.65 324.04,294.5 324.04,305.98 C324.04,326.24 318.59,341.56 307.84,351.52 C297.09,361.48 282.53,366.45 264.45,366.45 C256.023647,366.517248 247.635543,365.310279 239.57,362.87 C231.93,360.49 225.72,357.61 221.11,354.3 C217.052927,351.515289 213.430344,348.145445 210.36,344.3 C207.64,340.72 206.36,337.7 206.36,335.09 C206.41612,333.079377 207.205725,331.158715 208.58,329.69 L208.57,329.63 Z M128.83,453.11 L296.96,413.11 C299.21742,412.571572 301.590658,413.277552 303.186737,414.962302 C304.782816,416.647052 305.359576,419.054959 304.7,421.28 L296,450.51 L453.2,413.11 C455.45742,412.571572 457.830658,413.277552 459.426737,414.962302 C461.022816,416.647052 461.599576,419.054959 460.94,421.28 L452.27,450.51 L609.47,413.11 C611.72742,412.571572 614.100658,413.277552 615.696737,414.962302 C617.292816,416.647052 617.869576,419.054959 617.21,421.28 L608.54,450.51 L765.74,413.11 C767.999705,412.574102 770.373657,413.284449 771.967611,414.973462 C773.561565,416.662475 774.133361,419.073551 773.467611,421.298462 C772.80186,423.523373 770.999705,425.224102 768.74,425.76 L600.61,465.76 C598.35258,466.298428 595.979342,465.592448 594.383263,463.907698 C592.787184,462.222948 592.210424,459.815041 592.87,457.59 L601.54,428.36 L444.34,465.76 C442.08258,466.298428 439.709342,465.592448 438.113263,463.907698 C436.517184,462.222948 435.940424,459.815041 436.6,457.59 L445.27,428.36 L288.07,465.76 C285.81258,466.298428 283.439342,465.592448 281.843263,463.907698 C280.247184,462.222948 279.670424,459.815041 280.33,457.59 L289,428.36 L131.8,465.76 C131.305299,465.878067 130.798593,465.93847 130.29,465.94 C126.983263,465.951866 124.194638,463.479226 123.810649,460.194838 C123.426659,456.910451 125.569705,453.861232 128.79,453.11 L128.83,453.11 Z M219.36,568.38 C219.36,586.66 214.64,600.38 205.36,609.03 C196.08,617.68 183.68,622.03 168.41,622.03 L131.51,622.03 L131.51,690.84 C131.51,695.17 128.92,697.76 124.59,697.76 C120.26,697.76 117.67,695.17 117.67,690.84 L117.67,518.64 C117.67,516.86 118.32,512.64 124.31,511.98 L124.58,511.98 L168.38,511.98 C183.63,511.98 196.06,516.32 205.32,524.89 C214.58,533.46 219.32,547.14 219.32,565.43 L219.36,568.38 Z M360.87,727.12 C361.533457,728.352283 361.903078,729.721252 361.95,731.12 C362.033205,733.000791 361.322464,734.830022 359.991243,736.161243 C358.660022,737.492464 356.830791,738.203205 354.95,738.12 C353.896221,738.11813 352.861519,737.838761 351.95,737.31 C350.899467,736.658391 350.007755,735.780345 349.34,734.74 C348.62,733.74 348.06,732.9 347.65,732.28 L347.49,731.96 L346.31,728.7 C345.91,727.92 345.65,727.45 345.49,727.17 L345.26,727.17 L344.84,726.35 L296.63,632.35 L254.05,632.35 L254.05,731.15 C254.05,735.65 251.57,738.15 247.05,738.15 C242.53,738.15 240.05,735.67 240.05,731.15 L240.05,519.6 C240.05,517.4 240.93,513.6 246.86,512.94 L297.78,512.94 C316.68,512.94 332.23,517.65 344,526.94 C355.77,536.23 361.89,551.64 361.89,572.49 C361.89,606.93 344.98,626.76 311.64,631.49 L360.87,727.12 Z M459,644.64 C463.246667,644.64 465.373333,647.016667 465.38,651.77 C465.38,656.023333 463.253333,658.15 459,658.15 L399,658.15 L399,775.22 L525.79,775.22 C530.043333,775.22 532.17,777.596667 532.17,782.35 C532.17,786.603333 530.043333,788.73 525.79,788.73 L392.2,788.73 C387.7,788.73 385.45,786.48 385.45,781.98 L385.45,521.19 C385.45,516.69 387.7,514.44 392.2,514.44 L525.79,514.44 C530.043333,514.44 532.17,516.566667 532.17,520.82 C532.17,525.573333 530.043333,527.95 525.79,527.95 L399,527.95 L399,644.65 L459,644.64 Z M643.77,724.49 C632.69,734.74 617.57,739.93 598.83,739.93 C590.082311,740.000953 581.374084,738.750178 573,736.22 C565.08,733.75 558.65,730.76 553.88,727.34 C549.685777,724.461626 545.941701,720.977041 542.77,717 C540.01,713.36 538.67,710.33 538.67,707.74 C538.734283,705.789092 539.509619,703.928997 540.85,702.51 C542.39,700.72 543.85,699.86 545.33,699.86 C546.81,699.86 548.69,701.25 551.33,704.51 C553.57,707.26 556.16,710.26 559.03,713.42 C561.9,716.58 566.61,719.36 573.36,722 C580.11,724.64 588.19,726 597.28,726 C613.41,726 625.79,721.9 634.07,713.81 C642.35,705.72 646.53,693.81 646.53,678.26 C646.53,668.02 644.7,659.26 641.08,652.36 C637.874282,645.8902 632.964805,640.41717 626.88,636.53 C620.626732,632.715387 613.998721,629.552171 607.1,627.09 L585.53,619.5 C578.407687,617.155538 571.579303,613.998039 565.18,610.09 C558.689278,605.99337 553.413379,600.234076 549.9,593.41 C546.05,586.24 544.1,577.36 544.1,567.02 C544.1,556.49 546.05,547.32 549.88,539.75 C553.71,532.18 559.06,526.39 565.69,522.75 C571.760835,519.311259 578.289388,516.752362 585.08,515.15 C591.7762,513.680181 598.61447,512.955774 605.47,512.99 C616.890766,512.856493 628.25367,514.630891 639.09,518.24 C650,522 655,525.78 655,530.24 C654.916423,532.213781 654.157409,534.098961 652.85,535.58 C651.34,537.47 649.72,538.42 648.03,538.42 C647.19,538.42 645.75,538.05 640.91,535.34 C636.30085,532.971571 631.462578,531.07848 626.47,529.69 C619.544449,527.721432 612.369222,526.771473 605.17,526.87 C597.558092,526.781289 589.97323,527.791706 582.65,529.87 C576.19,531.8 570.4,535.87 565.46,541.99 C560.52,548.11 558.04,556.19 558.04,566.12 C558.04,574.52 559.85,581.66 563.43,587.36 C566.838785,592.927174 571.736573,597.43009 577.57,600.36 C583.94981,603.517486 590.538592,606.233855 597.29,608.49 C604.46,610.91 611.79,613.63 619.1,616.57 C626.282202,619.451958 633.112871,623.142398 639.46,627.57 C645.73,631.96 650.86,638.45 654.71,646.87 C658.56,655.29 660.47,665.52 660.47,677.43 C660.51,698.35 654.87,714.21 643.76,724.49 L643.77,724.49 Z M765.92,686.38 C756.67,694.94 744.07,699.29 728.49,699.29 C721.242168,699.348298 714.027215,698.309885 707.09,696.21 C701.428334,694.592844 696.056089,692.095694 691.17,688.81 C687.654637,686.392813 684.517177,683.467661 681.86,680.13 C679.44,676.94 678.27,674.23 678.27,671.84 C678.322752,669.953085 679.062359,668.150293 680.35,666.77 C681.85,665.02 683.35,664.18 684.94,664.18 C686.53,664.18 688.35,665.41 690.81,668.43 C692.62,670.65 694.71,673.07 697.04,675.63 C699.16,677.97 702.92,680.21 708.24,682.29 C714.32226,684.514605 720.764973,685.589521 727.24,685.46 C740.04,685.46 749.82,682.24 756.33,675.89 C762.84,669.54 766.1,660.12 766.1,647.83 C766.1,639.7 764.65,632.83 761.8,627.32 C759.297736,622.247998 755.460166,617.95407 750.7,614.9 C745.678978,611.841159 740.357883,609.304592 734.82,607.33 L717.27,601.15 C711.38642,599.215288 705.745772,596.608041 700.46,593.38 C694.996887,589.94318 690.550437,585.110082 687.58,579.38 C684.35,573.38 682.71,565.93 682.71,557.3 C682.71,548.67 684.34,540.87 687.55,534.53 C690.448442,528.485526 695.11436,523.46391 700.93,520.13 C705.977623,517.274361 711.405115,515.149827 717.05,513.82 C722.592378,512.592976 728.253448,511.9826 733.93,512 C743.367043,511.889982 752.756198,513.356827 761.71,516.34 C771.11,519.61 775.49,523.1 775.49,527.34 C775.433713,529.229237 774.727297,531.041195 773.49,532.47 C772.02,534.31 770.37,535.25 768.6,535.25 C767.77,535.25 766.6,535.04 762.2,532.58 C758.525602,530.696709 754.669063,529.19229 750.69,528.09 C745.162798,526.517786 739.435902,525.759815 733.69,525.84 C727.607224,525.759866 721.544725,526.558095 715.69,528.21 C710.365486,529.922249 705.692777,533.223505 702.3,537.67 C698.48,542.39 696.54,548.74 696.54,556.53 C696.54,563.13 697.95,568.72 700.74,573.16 C703.393404,577.491303 707.202977,580.996109 711.74,583.28 C716.884382,585.823473 722.196793,588.011919 727.64,589.83 C733.5,591.83 739.5,594.04 745.46,596.44 C751.395098,598.808559 757.041415,601.844754 762.29,605.49 C767.58,609.19 771.89,614.65 775.12,621.7 C778.35,628.75 779.92,637.22 779.92,647.1 C779.95,664.54 775.23,677.76 765.92,686.38 L765.92,686.38 Z" id="Shape"></path>
10
- <path d="M168.39,525.81 L131.51,525.81 L131.51,608.24 L168.39,608.24 C180.34,608.24 189.61,604.91 195.94,598.35 C202.27,591.79 205.52,581.68 205.52,568.35 L205.52,565.35 C205.52,552.06 202.3,542.03 195.95,535.52 C189.6,529.01 180.34,525.81 168.39,525.81 L168.39,525.81 Z" id="Shape"></path>
11
- </g>
12
- </g>
13
- </svg>
@@ -1,84 +0,0 @@
1
- body {
2
- font-family: sans-serif;
3
- margin: 2rem;
4
- padding: 0;
5
- background: hsl(23,39%,26%);
6
- color: #fefefe;
7
- }
8
-
9
- main {
10
- color: #000;
11
- background: #fefefe;
12
- padding: 2rem;
13
- border-radius: 0.5rem;
14
- }
15
-
16
- header {
17
- display: flex;
18
- flex-direction: row;
19
- align-items: center;
20
- margin-bottom: 1rem;
21
- }
22
-
23
- #logo {
24
- max-width: 4rem;
25
- max-height: 4rem;
26
- }
27
-
28
- #title {
29
- margin-left: 1rem;
30
- }
31
-
32
- footer {
33
- margin: 4rem 1rem;
34
- text-align: center;
35
- }
36
- footer a {
37
- color: #fefefe;
38
- }
39
-
40
- pre {
41
- overflow: scroll;
42
- }
43
-
44
- code {
45
- display: block;
46
- color: #000;
47
- background: hsl(23,39%,90%);
48
- padding: 1rem;
49
- border-radius: 0.5rem;
50
- }
51
-
52
- h2, a {
53
- color: hsl(23,39%,26%);
54
- }
55
-
56
- h3 {
57
- color: hsl(23,39%,5%);
58
- }
59
-
60
- table td, table th {
61
- text-align: left;
62
- padding: 0.25rem;
63
- }
64
-
65
- @media (prefers-color-scheme: dark) {
66
- h2, a {
67
- color: hsl(23,39%,90%);
68
- }
69
-
70
- h3 {
71
- color: hsl(23,39%,85%);
72
- }
73
-
74
- main {
75
- color: hsl(23,39%,85%);
76
- background: hsl(23,39%,10%);
77
- }
78
-
79
- code {
80
- color: hsl(23,39%,85%);
81
- background: hsl(23,39%,7%);
82
- }
83
- }
84
-