staticky 0.3.0 → 0.4.0

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +0 -3
  3. data/CHANGELOG.md +4 -0
  4. data/lib/staticky/builder.rb +1 -1
  5. data/lib/staticky/cli/commands/generate.rb +14 -14
  6. data/lib/staticky/environment.rb +1 -0
  7. data/lib/staticky/generator.rb +25 -14
  8. data/lib/staticky/phlex/view_helpers.rb +2 -2
  9. data/lib/staticky/resources/plugins/phlex.rb +1 -1
  10. data/lib/staticky/version.rb +1 -1
  11. data/site_template/.ruby-version.erb +1 -0
  12. data/site_template/Dockerfile +6 -6
  13. data/site_template/Gemfile +0 -1
  14. data/site_template/app/views/application_component.rb +1 -1
  15. data/site_template/app/views/application_page.rb +1 -1
  16. data/site_template/app/views/errors/not_found.rb +3 -2
  17. data/site_template/app/views/errors/service_error.rb +3 -2
  18. data/site_template/app/views/layouts/error.rb +1 -1
  19. data/site_template/app/views/layouts/head.rb +14 -8
  20. data/site_template/app/views/layouts/site.rb +10 -4
  21. data/site_template/app/views/pages/home.rb +8 -4
  22. data/site_template/bin/setup +1 -1
  23. data/site_template/config/puma.rb +1 -2
  24. data/site_template/config/vite.json +5 -1
  25. data/site_template/frontend/entrypoints/application.js +1 -3
  26. data/site_template/frontend/stylesheets/application.css +105 -44
  27. data/site_template/lib/icon.rb +9 -7
  28. data/site_template/lib/vite_helpers.rb +8 -0
  29. data/site_template/package.json +4 -5
  30. data/site_template/spec/spec_helper.rb +2 -4
  31. data/site_template/spec/support/phlex.rb +18 -0
  32. data/site_template/tailwind.config.js +4 -73
  33. data/site_template/vite.config.ts +2 -1
  34. metadata +25 -28
  35. data/site_template/.ruby-version +0 -1
  36. data/site_template/postcss.config.js +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65d9999164be324b93ee59cb6602a46b0c703e6e5f543801d4173164644e3ae9
4
- data.tar.gz: '0834f3f08d1d8cf469b846cec8349e5427c0809a419cbeaf845bf8ed66e07535'
3
+ metadata.gz: 95ec4e3725971f7989581aedde8a783407054a2874e697b35799c108c4c86caa
4
+ data.tar.gz: 7075eae02b43e7c953c730ec7d35c693d2f4c62bf55b46716fa1ae2f7d1f9e52
5
5
  SHA512:
6
- metadata.gz: d762bb547a713f7c86e4de541c1ee81615b8d0b5ec6d70633b50a1ad77986addf27ae64b3fc133c7b9749267774093ff9c9b1c6be54c8294004503b7992b6e9b
7
- data.tar.gz: 1103439135f08b7558e51eaf8a147febf2924f333f7f8b4b4c84ceeed24173d84c8ddc40d8aa4e25dd4fa4877a30a4b40bf37e3c14d23f78bac3391f1da324c2
6
+ metadata.gz: 44fdd85409d28bf9a036190576e6ad938fb1964155f6d67f141fb63394b96ef7f750567fb763b75af5743d163a90cf9f95e1ee46fd3e5efd96e34aecb041674d
7
+ data.tar.gz: 3a2724aa09955659477e37cd23b6d8fde2bc62dea6fefb3d14c3effb937cea12da05e7c2d4aee8421bbb14b9bcf2435ef1725f5544605886ccc4963bcf93ef4f
data/.rubocop.yml CHANGED
@@ -7,8 +7,5 @@ inherit_gem:
7
7
  - config/default.yml
8
8
  - config/capybara.yml
9
9
 
10
- AllCops:
11
- TargetRubyVersion: 3.3
12
-
13
10
  Lint/NumberConversion:
14
11
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.1] - 202-12-09
4
+
5
+ - Fixes flashes of unstyled content by adding `vite_stylesheet_tag`
6
+
3
7
  ## [0.3.0] - 2024-12-09
4
8
 
5
9
  - Adds live reloading of pages during development using server side events
@@ -14,7 +14,7 @@ module Staticky
14
14
 
15
15
  def self.call(...) = new(...).call
16
16
 
17
- def on(event_type, &block) = subscribe(event_type, &block)
17
+ def on(event_type, &) = subscribe(event_type, &)
18
18
 
19
19
  def call
20
20
  publish("started")
@@ -7,25 +7,25 @@ module Staticky
7
7
  desc "Create new site"
8
8
 
9
9
  argument :path,
10
- required: true,
11
- desc: "Relative path where the site will be generated"
10
+ required: true,
11
+ desc: "Relative path where the site will be generated"
12
12
 
13
13
  option :url,
14
- default: "https://example.com",
15
- desc: "Site URL",
16
- aliases: ["-u"]
14
+ default: "https://example.com",
15
+ desc: "Site URL",
16
+ aliases: ["-u"]
17
17
  option :title,
18
- default: "Example",
19
- desc: "Site title",
20
- aliases: ["-t"]
18
+ default: "Example",
19
+ desc: "Site title",
20
+ aliases: ["-t"]
21
21
  option :description,
22
- default: "Example site",
23
- desc: "Site description",
24
- aliases: ["-d"]
22
+ default: "Example site",
23
+ desc: "Site description",
24
+ aliases: ["-d"]
25
25
  option :twitter,
26
- default: "",
27
- desc: "Twitter handle",
28
- aliases: ["-x"]
26
+ default: "",
27
+ desc: "Twitter handle",
28
+ aliases: ["-x"]
29
29
 
30
30
  def call(path:, **)
31
31
  path = Pathname.new(path).expand_path
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Staticky
4
4
  Environment = Data.define(:name) do
5
+ def production? = name == :production
5
6
  def development? = name == :development
6
7
  def test? = name == :test
7
8
  end
@@ -24,34 +24,41 @@ module Staticky
24
24
 
25
25
  def call(output_dir, **)
26
26
  view_context = ViewContext.new(**)
27
- output_dir = Pathname.new(output_dir).expand_path
27
+ output_dir = Pathname(output_dir).expand_path
28
28
 
29
- Pathname.glob(@path.join("**/*"), File::FNM_DOTMATCH).each do |file|
30
- build_file(file:, output_dir:, view_context:)
29
+ Pathname.glob(@path.join("**/*"), File::FNM_DOTMATCH).each do |input_path|
30
+ relative_path = input_path.relative_path_from(@path)
31
+ output_path = output_dir.join(relative_path)
32
+ build_file(input_path:, output_path:, view_context:)
31
33
  end
32
34
  end
33
35
 
34
36
  private
35
37
 
36
- def build_file(file:, output_dir:, view_context:)
37
- return if file.directory?
38
-
39
- relative_path = file.relative_path_from(@path)
40
- target = output_dir.join(relative_path)
38
+ def build_file(input_path:, output_path:, view_context:)
39
+ return if input_path.directory?
41
40
 
42
41
  # This handles files like:
43
42
  # - index.html.erb -> index.html
44
43
  # - site.erb -> site.rb
45
- if target.extname == ".erb"
46
- target = target.sub_ext("")
47
- target = target.sub_ext(".rb") if target.extname == ""
44
+ # - .ruby-version.erb -> .ruby-version
45
+ output_path = output_path.then do |filepath|
46
+ next filepath unless filepath.extname == ".erb"
47
+
48
+ # Replace the .erb with nothing. Skip if its not a ruby file
49
+ # site.erb -> site
50
+ filepath = filepath.sub_ext("")
51
+ next filepath unless filepath.extname.empty?
52
+ next filepath if dotfile?(filepath)
53
+
54
+ filepath.sub_ext(".rb")
48
55
  end
49
56
 
50
- build_template(file:, target:, view_context:)
57
+ build_template(input_path:, output_path:, view_context:)
51
58
  end
52
59
 
53
- def build_template(file:, target:, view_context:)
54
- files.write(target, render_template(file, view_context))
60
+ def build_template(input_path:, output_path:, view_context:)
61
+ files.write(output_path, render_template(input_path, view_context))
55
62
  end
56
63
 
57
64
  def render_template(file, view_context)
@@ -59,5 +66,9 @@ module Staticky
59
66
 
60
67
  Tilt::ERBTemplate.new(file).render(view_context)
61
68
  end
69
+
70
+ def dotfile?(path)
71
+ path.basename.to_s.start_with?(".")
72
+ end
62
73
  end
63
74
  end
@@ -4,12 +4,12 @@ module Staticky
4
4
  module Phlex
5
5
  module ViewHelpers
6
6
  def helpers
7
- @_view_context
7
+ context[:helpers]
8
8
  end
9
9
 
10
10
  def staticky_live_reload_js(base_path = "/")
11
11
  script(type: :module) do
12
- unsafe_raw Staticky::Utils.live_reload_js(base_path)
12
+ raw safe(Staticky::Utils.live_reload_js(base_path))
13
13
  end
14
14
  end
15
15
 
@@ -31,7 +31,7 @@ module Staticky
31
31
  end
32
32
 
33
33
  def build(view_context: ViewContext.new(self))
34
- component.call(view_context:)
34
+ component.call(context: { helpers: view_context })
35
35
  end
36
36
  end
37
37
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Staticky
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -0,0 +1 @@
1
+ <%= RUBY_VERSION %>
@@ -1,5 +1,5 @@
1
1
  # Use an official Ruby runtime based on Alpine as a parent image
2
- FROM ruby:3.3-alpine AS builder
2
+ FROM ruby:3.3.6-alpine AS builder
3
3
 
4
4
  ENV RACK_ENV="production" \
5
5
  NODE_ENV="production" \
@@ -10,26 +10,26 @@ ENV RACK_ENV="production" \
10
10
  RUN gem update --system --no-document && \
11
11
  gem install -N bundler
12
12
 
13
- # Install necessary packages including Node.js and Yarn
13
+ # Install necessary packages including Node.js and pnpm
14
14
  RUN apk add --no-cache build-base nodejs npm git && \
15
- npm install -g yarn
15
+ npm install -g pnpm
16
16
 
17
17
  # Set the working directory
18
18
  WORKDIR /app
19
19
 
20
20
  # Copy Gemfile and other necessary files
21
- COPY --link Gemfile Gemfile.lock .ruby-version package.json yarn.lock ./
21
+ COPY --link Gemfile Gemfile.lock .ruby-version package.json pnpm-lock.yaml ./
22
22
 
23
23
  # Install dependencies
24
24
  RUN bundle install && \
25
- yarn install --frozen-lockfile && \
25
+ pnpm install --frozen-lockfile && \
26
26
  rm -rf /root/.bundle/cache /usr/local/bundle/cache /var/cache/apk/*
27
27
 
28
28
  # Copy the rest of the application code
29
29
  COPY --link . .
30
30
 
31
31
  # Build the static site (e.g., using Jekyll)
32
- RUN bin/rake site:build
32
+ RUN bin/vite build && bin/rake site:build
33
33
 
34
34
  # Use an official Nginx image based on Alpine to serve the static site
35
35
  FROM nginx:stable-alpine
@@ -21,7 +21,6 @@ gem "zeitwerk"
21
21
  group :test do
22
22
  gem "capybara", require: false
23
23
  gem "debug"
24
- gem "phlex-testing-capybara"
25
24
  gem "rspec"
26
25
  end
27
26
 
@@ -11,7 +11,7 @@ class ApplicationComponent < Protos::Component
11
11
  end
12
12
 
13
13
  def helpers
14
- @_view_context ||= NullViewContext.new # rubocop:disable Naming/MemoizedInstanceVariableName
14
+ context[:helpers] ||= NullViewContext.new
15
15
  end
16
16
 
17
17
  def asset_path(...)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ApplicationPage < ApplicationComponent
4
- def around_template(&block) = render Layouts::Page.new(&block)
4
+ def around_template(&) = render Layouts::Site.new(&)
5
5
  end
@@ -4,11 +4,12 @@ module Errors
4
4
  class NotFound < ApplicationPage
5
5
  include Protos::Typography
6
6
 
7
- def self.layout = Layouts::Error
7
+ def around_template(&) = render Layouts::Error.new(&)
8
8
 
9
9
  def view_template
10
+ span(class: "font-thin text-8xl") { "404" }
10
11
  h1 { "Page not found." }
11
- link_to("Back to home", Pages::Home, class: "link")
12
+ link_to("Back to home", Pages::Home, class: "btn mt-sm")
12
13
  end
13
14
  end
14
15
  end
@@ -4,11 +4,12 @@ module Errors
4
4
  class ServiceError < ApplicationPage
5
5
  include Protos::Typography
6
6
 
7
- def self.layout = Layouts::Error
7
+ def around_template(&) = render Layouts::Error.new(&)
8
8
 
9
9
  def view_template
10
+ span(class: "font-thin text-8xl") { "500" }
10
11
  h1 { "Something went wrong." }
11
- link_to("Back to home", Pages::Home, class: "link")
12
+ link_to("Back to home", Pages::Home, class: "btn mt-sm")
12
13
  end
13
14
  end
14
15
  end
@@ -3,7 +3,7 @@
3
3
  module Layouts
4
4
  class Error < Site
5
5
  def view_template(&)
6
- div(class: "grid place-items-center h-[--main-scene]") do
6
+ div(class: "grid place-items-center h-screen") do
7
7
  section(class: "flex flex-col place-items-center gap-sm", &)
8
8
  end
9
9
  end
@@ -11,7 +11,7 @@ module Layouts
11
11
  meta name: "description", content: @description
12
12
  meta charset: "utf-8"
13
13
  meta name: "viewport",
14
- content: "width=device-width,initial-scale=1,viewport-fit=cover"
14
+ content: "width=device-width,initial-scale=1,viewport-fit=cover"
15
15
  meta name: "turbo-cache-control", content: "no-preview"
16
16
  meta name: "turbo-refresh-method", content: "morph"
17
17
  meta name: "turbo-refresh-scroll", content: "preserve"
@@ -22,16 +22,16 @@ module Layouts
22
22
  meta name: "apple-mobile-web-app-status-bar-style", content: "default"
23
23
  meta name: "apple-mobile-web-app-title", content: @title
24
24
 
25
- link rel: "canonical", href: ::Site.url_for(helpers.current_path)
25
+ link rel: "canonical", href: ::Site.url_for(helpers.current_path).to_s
26
26
  link rel: "apple-touch-icon", href: "/apple-touch-icon.png"
27
27
  link rel: "icon",
28
- type: "image/png",
29
- sizes: "32x32",
30
- href: "/favicon-32x32.png"
28
+ type: "image/png",
29
+ sizes: "32x32",
30
+ href: "/favicon-32x32.png"
31
31
  link rel: "icon",
32
- type: "image/png",
33
- sizes: "16x16",
34
- href: "/favicon-16x16.png"
32
+ type: "image/png",
33
+ sizes: "16x16",
34
+ href: "/favicon-16x16.png"
35
35
  link rel: "manifest", href: "/site.webmanifest"
36
36
 
37
37
  meta property: "og:title", content: @title
@@ -44,6 +44,8 @@ module Layouts
44
44
  meta name: "twitter:site", content: ::Site.twitter
45
45
  meta name: "twitter:creator", content: ::Site.twitter
46
46
 
47
+ stylesheet_tag "stylesheets/syntax", media: "screen"
48
+ stylesheet_tag "stylesheets/application", media: "screen"
47
49
  javascript_tag "application"
48
50
 
49
51
  if Staticky.env.development?
@@ -58,5 +60,9 @@ module Layouts
58
60
  def javascript_tag(...)
59
61
  vite_javascript_tag(...)
60
62
  end
63
+
64
+ def stylesheet_tag(...)
65
+ vite_stylesheet_tag(...)
66
+ end
61
67
  end
62
68
  end
@@ -10,16 +10,22 @@ module Layouts
10
10
  end
11
11
  end
12
12
 
13
- def view_template(&block)
13
+ def view_template(&)
14
14
  render UI::Navbar.new(class: css[:navbar])
15
- main(**attrs, &block)
15
+ main(**attrs, &)
16
16
  render UI::Footer.new(class: css[:footer])
17
17
  end
18
18
 
19
19
  private
20
20
 
21
- def head(&block)
22
- render Head.new(&block)
21
+ def head(&)
22
+ render Head.new(&)
23
+ end
24
+
25
+ def theme
26
+ {
27
+ container: "min-h-screen"
28
+ }
23
29
  end
24
30
  end
25
31
  end
@@ -6,15 +6,19 @@ module Pages
6
6
 
7
7
  def view_template
8
8
  render Protos::Hero.new(
9
- class: "h-96",
9
+ class: "min-h-96",
10
10
  style: "background-image: url(#{asset_path("images/hero.jpg")})"
11
11
  ) do |hero|
12
- hero.overlay(class: "opacity-90")
12
+ hero.overlay
13
13
  hero.content(class: "flex-col text-white") do
14
14
  h1 { "Ruby maximalism" }
15
- p(margin: false) { "Zen vibes only" }
15
+ h2(margin: false, size: :sm) { "Zen vibes only" }
16
16
 
17
- link_to("Learn more", Errors::NotFound)
17
+ link_to(
18
+ "Learn more",
19
+ Errors::NotFound,
20
+ class: "btn btn-primary mt-md"
21
+ )
18
22
  end
19
23
  end
20
24
  end
@@ -20,5 +20,5 @@ FileUtils.chdir APP_ROOT do
20
20
  system! "bundle binstubs --force bundler rubocop rspec-core vite_ruby rake"
21
21
 
22
22
  puts "\n== Installing javascript dependencies =="
23
- system! "yarn install"
23
+ system! "pnpm install"
24
24
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Run in single threaded mode
4
- threads 0, 1
3
+ threads 3
5
4
 
6
5
  # Specifies the `port` that Puma will listen on to receive requests; default is
7
6
  # 3000.
@@ -2,8 +2,12 @@
2
2
  "all": {
3
3
  "publicDir": "build",
4
4
  "sourceCodeDir": "frontend",
5
+ "additionalEntrypoints": [
6
+ "~/{images,stylesheets}/**/*"
7
+ ],
5
8
  "watchAdditionalPaths": [
6
- "app/**/*.rb"
9
+ "app/**/*.rb",
10
+ "config/site.rb"
7
11
  ]
8
12
  },
9
13
  "development": {
@@ -1,7 +1,5 @@
1
1
  import "@fontsource-variable/inter"
2
+ import * as Turbo from "@hotwired/turbo"
2
3
  import "protos-stimulus"
3
4
 
4
- import "~/stylesheets/application.css"
5
- import "~/stylesheets/syntax.css"
6
-
7
5
  import "~/controllers"
@@ -1,61 +1,122 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
1
+ @import "tailwindcss";
2
+ @config "../../tailwind.config.js";
3
+ @plugin "daisyui";
4
+
5
+ @plugin "daisyui/theme" {
6
+ name: "onedark";
7
+ default: true;
8
+ prefersdark: true;
9
+ color-scheme: "dark";
10
+
11
+ --color-base-100: oklch(35.07% 0.0193 260.66);
12
+ --color-base-200: oklch(29.25% 0.0157 264.3);
13
+ --color-base-300: oklch(25.15% 0.0122 264.33);
14
+ --color-neutral: oklch(17% 0.0157 260);
15
+ --color-neutral-content: oklch(86% 0.02 250);
16
+ --color-base-content: oklch(84.45% 0.0119 264.5);
17
+ --color-primary: oklch(0.7 0.15 240);
18
+ --color-primary-content: oklch(15% 0.091 265);
19
+ --color-secondary: oklch(0.8 0.1 80);
20
+ --color-secondary-content: oklch(10% 0.1 57);
21
+ --color-accent: oklch(0.7 0.2 310);
22
+ --color-accent-content: oklch(20% 0.149 300);
23
+ --color-info: oklch(72.31% 0.0916 200);
24
+ --color-info-content: oklch(20% 0.066 240);
25
+ --color-success: oklch(76.83% 0.1103 133);
26
+ --color-success-content: oklch(20% 0.077 169);
27
+ --color-warning: oklch(82.49% 0.097 82);
28
+ --color-warning-content: oklch(15% 0.112 46);
29
+ --color-error: oklch(67.09% 0.1448 17);
30
+ --color-error-content: oklch(20% 0.105 12);
31
+
32
+ --radius-selector: 8px;
33
+ --radius-field: 8px;
34
+ --radius-box: 8px;
35
+
36
+ --size-selector: 4px;
37
+ --size-field: 4px;
38
+
39
+ --border: 1px;
40
+ --depth: 0;
41
+ --noise: 0;
42
+ }
43
+
44
+ @theme inline {
45
+ --font-*: initial;
46
+ --font-sans: Inter Variable, ui-sans-serif, system-ui, sans-serif,
47
+ "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
48
+ --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
49
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
50
+ "Liberation Mono", "Courier New", monospace;
51
+
52
+ --spacing: 4px;
53
+ --spacing-xs: clamp(8px, 1%, 16px);
54
+ --spacing-sm: clamp(12px, 3%, 18px);
55
+ --spacing-md: clamp(20px, 6%, 40px);
56
+ --spacing-lg: clamp(48px, 12%, 96px);
57
+ --spacing-xl: clamp(96px, 24%, 192px);
58
+
59
+ --gap: 4px;
60
+ --gap-xs: clamp(8px, 1vmax, 16px);
61
+ --gap-sm: clamp(16px, 3vmax, 40px);
62
+ --gap-md: clamp(24px, 6vmax, 48px);
63
+ --gap-lg: clamp(48px, 8vmax, 64px);
64
+ --gap-xl: clamp(64px, 12vmax, 96px);
65
+ }
4
66
 
5
67
  @layer base {
6
68
  :root {
7
- --spacing-xs: clamp(0.5rem, 1%, 1rem);
8
- --spacing-sm: clamp(0.75rem, 3%, 1.2rem);
9
- --spacing-md: clamp(1.25rem, 6%, 2.5rem);
10
- --spacing-lg: clamp(3rem, 12%, 6rem);
11
- --spacing-xl: clamp(6rem, 24%, 12rem);
12
- --spacing-gap-xs: clamp(0.5rem, 1vmax, 1rem);
13
- --spacing-gap-sm: clamp(1rem, 3vmax, 1.5rem);
14
- --spacing-gap-md: clamp(1.5rem, 6vmax, 3rem);
15
- --spacing-gap-lg: clamp(3rem, 8vmax, 4rem);
16
- --spacing-gap-xl: clamp(4rem, 12vmax, 6rem);
17
- --shadow-color: var(--b3);
18
- --box-shadow-sm:
19
- 0.3px 0.5px 0.5px oklch(var(--shadow-color) / 0.49),
20
- 0.5px 0.7px 0.8px -1.9px oklch(var(--shadow-color) / 0.38),
21
- 1.3px 1.9px 2.2px -3.7px oklch(var(--shadow-color) / 0.27);
22
- --box-shadow-md:
23
- 0.3px 0.5px 0.5px oklch(var(--shadow-color) / 0.51),
24
- 0.8px 1.2px 1.4px -1.2px oklch(var(--shadow-color) / 0.43),
25
- 2.3px 3.6px 4px -2.5px oklch(var(--shadow-color) / 0.34),
26
- 6.3px 9.6px 10.8px -3.7px oklch(var(--shadow-color) / 0.26);
27
- --box-shadow-lg:
28
- 0.3px 0.5px 0.5px oklch(var(--shadow-color) / 0.54),
29
- 1.3px 1.9px 2.2px -0.6px oklch(var(--shadow-color) / 0.49),
30
- 2.7px 4.1px 4.6px -1.2px oklch(var(--shadow-color) / 0.44),
31
- 5.5px 8.4px 9.4px -1.9px oklch(var(--shadow-color) / 0.39),
32
- 10.6px 16.1px 18.1px -2.5px oklch(var(--shadow-color) / 0.34),
33
- 18.7px 28.4px 31.9px -3.1px oklch(var(--shadow-color) / 0.29),
34
- 30.7px 46.6px 52.3px -3.7px oklch(var(--shadow-color) / 0.23);
35
69
  --navbar-height: 64px;
36
70
  --main-scene: calc(100vh - var(--navbar-height));
37
- --viewport-padding: var(--spacing-md);
38
71
  }
39
72
 
40
- body {
41
- @apply bg-base-400;
73
+ /* Chrome, Edge, and Safari */
74
+ *::-webkit-scrollbar {
75
+ width: 0.66rem;
76
+ background: var(--color-base-300);
42
77
  }
43
78
 
44
- .prose pre {
45
- @apply bg-base-300 border;
79
+ *::-webkit-scrollbar-track {
80
+ background: var(--color-base-200);
81
+ border-radius: 0px;
46
82
  }
47
83
 
48
- * {
49
- scrollbar-color: theme("colors.base-200") theme("colors.base-300");
50
- border-color: theme("colors.base-200");
84
+ *::-webkit-scrollbar-thumb {
85
+ background-color: var(--color-base-100);
86
+ border-radius: var(--radius-md);
87
+ border-style: var(--tw-border-style);
88
+ border-width: 1px;
51
89
  }
52
90
 
53
- /* Chrome, Edge, and Safari */
54
- *::-webkit-scrollbar {
55
- background: theme("colors.base-300")
91
+ /* Reset number input type styles */
92
+ /* Chrome, Safari, Edge, Opera */
93
+ input::-webkit-outer-spin-button,
94
+ input::-webkit-inner-spin-button {
95
+ -webkit-appearance: none;
96
+ appearance: none;
97
+ margin: 0;
98
+ }
99
+ }
100
+
101
+ @layer utilities {
102
+ /* Firefox */
103
+ input[type=number] {
104
+ -moz-appearance: textfield;
105
+ appearance: textfield;
56
106
  }
57
107
 
58
- *::-webkit-scrollbar-track {
59
- background: theme("colors.base-200");
108
+ .btn-ghost {
109
+ border: 0;
60
110
  }
61
111
  }
112
+
113
+ *,
114
+ ::before,
115
+ ::after,
116
+ ::backdrop,
117
+ ::file-selector-button {
118
+ /* scrollbar-width: thin; */
119
+ scrollbar-color: var(--color-base-100) var(--color-base-200);
120
+ /* border-color: color-mix(in oklab, currentColor, black calc(var(--depth) * 50%)); */
121
+ border-color: color-mix(in oklch, var(--color-base-content) 20%, transparent);
122
+ }
@@ -1,6 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Icon < ApplicationComponent
4
+ SIZES = {
5
+ xs: "w-3 h-3",
6
+ sm: "w-4 h-4",
7
+ md: "w-5 h-5",
8
+ lg: "w-7 h-7"
9
+ }.freeze
10
+
4
11
  param :name, reader: false
5
12
  option :variant, reader: false, default: -> { }
6
13
  option :size, default: -> { :md }, reader: false
@@ -23,17 +30,12 @@ class Icon < ApplicationComponent
23
30
  end
24
31
 
25
32
  def size
26
- {
27
- xs: "w-3 h-3",
28
- sm: "w-4 h-4",
29
- md: "w-5 h-5",
30
- lg: "w-7 h-7"
31
- }.fetch(@size)
33
+ SIZES.fetch(@size)
32
34
  end
33
35
 
34
36
  def theme
35
37
  {
36
- container: tokens(size, "opacity-90", "inline-block")
38
+ container: [size, "inline-block", "opacity-90"]
37
39
  }
38
40
  end
39
41
  end
@@ -6,6 +6,14 @@ module ViteHelpers
6
6
  script(src:, type: :module)
7
7
  end
8
8
 
9
+ def vite_stylesheet_tag(*names, **options)
10
+ style_paths = names.map { |name| vite_asset_path(name, type: :stylesheet) }
11
+
12
+ style_paths.each do |href|
13
+ link(href:, rel: :stylesheet, **options)
14
+ end
15
+ end
16
+
9
17
  def vite_javascript_tag(
10
18
  *names,
11
19
  type: :module,
@@ -15,11 +15,10 @@
15
15
  "@hotwired/stimulus": "^3.2.2",
16
16
  "@hotwired/turbo": "^8.0.12",
17
17
  "@tailwindcss/typography": "^0.5.15",
18
- "autoprefixer": "^10.4.20",
19
- "daisyui": "^4.12.20",
20
- "postcss": "^8.4.49",
21
- "protos-stimulus": "^0.0.4",
22
- "tailwindcss": "^3.4.16",
18
+ "@tailwindcss/vite": "^4.0.9",
19
+ "daisyui": "^5.0.0",
20
+ "protos-stimulus": "^0.1.0",
21
+ "tailwindcss": "^4.0.9",
23
22
  "vite": "^6.0.3",
24
23
  "vite-plugin-ruby": "^5.1.1"
25
24
  }
@@ -3,8 +3,6 @@
3
3
  require "./config/boot"
4
4
  Bundler.require(:test)
5
5
 
6
- require "capybara/rspec"
7
- require "phlex/testing/capybara"
8
6
  require "dry/inflector"
9
7
 
10
8
  inflector = Dry::Inflector.new
@@ -25,6 +23,6 @@ RSpec.configure do |config|
25
23
  metadata[:type] ||= inflector.singularize(type).to_sym
26
24
  end
27
25
  end
28
-
29
- config.include Phlex::Testing::Capybara::ViewHelper, type: :view
30
26
  end
27
+
28
+ Pathname.glob(Pathname(__dir__).join("support/**/*.rb")).each { |file| require file }
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "capybara/rspec"
4
+
5
+ module ComponentHelpers
6
+ def render(component, ...)
7
+ result = component.call(...)
8
+ @page = Capybara::Node::Simple.new(result)
9
+ end
10
+
11
+ def page
12
+ @page
13
+ end
14
+ end
15
+
16
+ RSpec.configure do |config|
17
+ config.include ComponentHelpers
18
+ end
@@ -1,87 +1,18 @@
1
- import defaultTheme from "tailwindcss/defaultTheme"
2
- import daisyui from "daisyui"
3
- import typography from "@tailwindcss/typography"
4
- import variableFonts from "./frontend/tailwindcss/variable_font_plugin"
5
-
6
1
  // For importing tailwind styles from protos gem
7
2
  import { execSync } from "child_process"
3
+ import typography from "@tailwindcss/typography"
4
+
8
5
  const output = execSync("bundle show protos", { encoding: "utf-8" });
9
6
  const protos_path = output.trim() + "/**/*.rb";
10
7
 
11
8
  /** @type {import("tailwindcss").Config} */
12
9
  const config = {
13
10
  content: [
14
- "./app/**/*.rb",
11
+ "./app/views/**/*.rb",
15
12
  "./lib/**/*.rb",
16
13
  protos_path
17
14
  ],
18
- theme: {
19
- fontFamily: {
20
- ...defaultTheme.fontFamily,
21
- sans: ["Inter Variable", ...defaultTheme.fontFamily.sans],
22
- },
23
- boxShadow: {
24
- sm: "var(--box-shadow-sm)",
25
- md: "var(--box-shadow-md)",
26
- lg: "var(--box-shadow-lg)"
27
- },
28
- extend: {
29
- colors: {
30
- "base-400": "#1e2227",
31
- },
32
- spacing: {
33
- xs: "var(--spacing-xs)",
34
- sm: "var(--spacing-sm)",
35
- md: "var(--spacing-md)",
36
- lg: "var(--spacing-lg)",
37
- xl: "var(--spacing-xl)",
38
- },
39
- gap: {
40
- xs: "var(--spacing-gap-xs)",
41
- sm: "var(--spacing-gap-sm)",
42
- md: "var(--spacing-gap-md)",
43
- lg: "var(--spacing-gap-lg)",
44
- xl: "var(--spacing-gap-xl)",
45
- },
46
- },
47
- },
48
- daisyui: {
49
- themes: [
50
- {
51
- onedark: {
52
- "primary": "#61afef",
53
- "secondary": "#e5c07b",
54
- "accent": "#c678dd",
55
- "neutral": "#545862",
56
- "neutral-content": "#c8ccd4",
57
- "base-100": "#3e4451",
58
- "base-200": "#353b45",
59
- "base-300": "#282c34",
60
- "base-content": "#b6bdca",
61
- "info": "#61afef",
62
- "success": "#98c379",
63
- "warning": "#e5c07b",
64
- "error": "#e06c75",
65
-
66
- "--rounded-box": "0.5rem", // border radius rounded-box utility class, used in card and other large boxes
67
- "--rounded-btn": "0.25rem", // border radius rounded-btn utility class, used in buttons and similar element
68
- "--rounded-badge": "1rem", // border radius rounded-badge utility class, used in badges and similar
69
- "--animation-btn": "0.25s", // duration of animation when you click on button
70
- "--animation-input": "0.2s", // duration of animation for inputs like checkbox, toggle, radio, etc
71
- "--btn-text-case": "uppercase", // set default text transform for buttons
72
- "--btn-focus-scale": "0.95", // scale transform of button when you focus on it
73
- "--border-btn": "1px", // border width of buttons
74
- "--tab-border": "1px", // border width of tabs
75
- "--tab-radius": "0.25rem", // border radius of tabs
76
- },
77
- },
78
- ]
79
- },
80
- plugins: [
81
- daisyui,
82
- typography,
83
- variableFonts
84
- ],
15
+ plugins: [typography]
85
16
  }
86
17
 
87
18
  export default config
@@ -1,9 +1,10 @@
1
1
  import { defineConfig } from "vite"
2
2
  import RubyPlugin from "vite-plugin-ruby"
3
+ import tailwindcss from "@tailwindcss/vite"
3
4
 
4
5
  export default defineConfig({
5
- server: { hmr: false },
6
6
  plugins: [
7
+ tailwindcss(),
7
8
  RubyPlugin(),
8
9
  ],
9
10
  })
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: staticky
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nolan J Tait
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-12-09 00:00:00.000000000 Z
10
+ date: 2025-03-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: dry-cli
@@ -16,28 +15,28 @@ dependencies:
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '1.1'
18
+ version: '1'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '1.1'
25
+ version: '1'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: dry-configurable
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
- version: '1.2'
32
+ version: '1'
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - "~>"
39
38
  - !ruby/object:Gem::Version
40
- version: '1.2'
39
+ version: '1'
41
40
  - !ruby/object:Gem::Dependency
42
41
  name: dry-container
43
42
  requirement: !ruby/object:Gem::Requirement
@@ -58,98 +57,98 @@ dependencies:
58
57
  requirements:
59
58
  - - "~>"
60
59
  - !ruby/object:Gem::Version
61
- version: '1.0'
60
+ version: '1'
62
61
  type: :runtime
63
62
  prerelease: false
64
63
  version_requirements: !ruby/object:Gem::Requirement
65
64
  requirements:
66
65
  - - "~>"
67
66
  - !ruby/object:Gem::Version
68
- version: '1.0'
67
+ version: '1'
69
68
  - !ruby/object:Gem::Dependency
70
69
  name: dry-inflector
71
70
  requirement: !ruby/object:Gem::Requirement
72
71
  requirements:
73
72
  - - "~>"
74
73
  - !ruby/object:Gem::Version
75
- version: '1.1'
74
+ version: '1'
76
75
  type: :runtime
77
76
  prerelease: false
78
77
  version_requirements: !ruby/object:Gem::Requirement
79
78
  requirements:
80
79
  - - "~>"
81
80
  - !ruby/object:Gem::Version
82
- version: '1.1'
81
+ version: '1'
83
82
  - !ruby/object:Gem::Dependency
84
83
  name: dry-logger
85
84
  requirement: !ruby/object:Gem::Requirement
86
85
  requirements:
87
86
  - - "~>"
88
87
  - !ruby/object:Gem::Version
89
- version: '1.0'
88
+ version: '1'
90
89
  type: :runtime
91
90
  prerelease: false
92
91
  version_requirements: !ruby/object:Gem::Requirement
93
92
  requirements:
94
93
  - - "~>"
95
94
  - !ruby/object:Gem::Version
96
- version: '1.0'
95
+ version: '1'
97
96
  - !ruby/object:Gem::Dependency
98
97
  name: dry-monitor
99
98
  requirement: !ruby/object:Gem::Requirement
100
99
  requirements:
101
100
  - - "~>"
102
101
  - !ruby/object:Gem::Version
103
- version: '1.0'
102
+ version: '1'
104
103
  type: :runtime
105
104
  prerelease: false
106
105
  version_requirements: !ruby/object:Gem::Requirement
107
106
  requirements:
108
107
  - - "~>"
109
108
  - !ruby/object:Gem::Version
110
- version: '1.0'
109
+ version: '1'
111
110
  - !ruby/object:Gem::Dependency
112
111
  name: dry-system
113
112
  requirement: !ruby/object:Gem::Requirement
114
113
  requirements:
115
114
  - - "~>"
116
115
  - !ruby/object:Gem::Version
117
- version: '1.0'
116
+ version: '1'
118
117
  type: :runtime
119
118
  prerelease: false
120
119
  version_requirements: !ruby/object:Gem::Requirement
121
120
  requirements:
122
121
  - - "~>"
123
122
  - !ruby/object:Gem::Version
124
- version: '1.0'
123
+ version: '1'
125
124
  - !ruby/object:Gem::Dependency
126
125
  name: phlex
127
126
  requirement: !ruby/object:Gem::Requirement
128
127
  requirements:
129
128
  - - "~>"
130
129
  - !ruby/object:Gem::Version
131
- version: '1.11'
130
+ version: '2'
132
131
  type: :runtime
133
132
  prerelease: false
134
133
  version_requirements: !ruby/object:Gem::Requirement
135
134
  requirements:
136
135
  - - "~>"
137
136
  - !ruby/object:Gem::Version
138
- version: '1.11'
137
+ version: '2'
139
138
  - !ruby/object:Gem::Dependency
140
139
  name: roda
141
140
  requirement: !ruby/object:Gem::Requirement
142
141
  requirements:
143
142
  - - "~>"
144
143
  - !ruby/object:Gem::Version
145
- version: '3.83'
144
+ version: '3'
146
145
  type: :runtime
147
146
  prerelease: false
148
147
  version_requirements: !ruby/object:Gem::Requirement
149
148
  requirements:
150
149
  - - "~>"
151
150
  - !ruby/object:Gem::Version
152
- version: '3.83'
151
+ version: '3'
153
152
  - !ruby/object:Gem::Dependency
154
153
  name: staticky-files
155
154
  requirement: !ruby/object:Gem::Requirement
@@ -170,14 +169,14 @@ dependencies:
170
169
  requirements:
171
170
  - - "~>"
172
171
  - !ruby/object:Gem::Version
173
- version: '2.4'
172
+ version: '2'
174
173
  type: :runtime
175
174
  prerelease: false
176
175
  version_requirements: !ruby/object:Gem::Requirement
177
176
  requirements:
178
177
  - - "~>"
179
178
  - !ruby/object:Gem::Version
180
- version: '2.4'
179
+ version: '2'
181
180
  description: Static site
182
181
  email:
183
182
  - nolanjtait@gmail.com
@@ -225,7 +224,7 @@ files:
225
224
  - site_template/.prettierrc
226
225
  - site_template/.rspec
227
226
  - site_template/.rubocop.yml
228
- - site_template/.ruby-version
227
+ - site_template/.ruby-version.erb
229
228
  - site_template/Dockerfile
230
229
  - site_template/Gemfile
231
230
  - site_template/Procfile.dev
@@ -269,7 +268,6 @@ files:
269
268
  - site_template/logs/.keep
270
269
  - site_template/nginx.conf
271
270
  - site_template/package.json
272
- - site_template/postcss.config.js
273
271
  - site_template/public/android-chrome-192x192.png
274
272
  - site_template/public/android-chrome-512x512.png
275
273
  - site_template/public/apple-touch-icon.png
@@ -280,6 +278,7 @@ files:
280
278
  - site_template/public/site.webmanifest.erb
281
279
  - site_template/public/sitemap.xml
282
280
  - site_template/spec/spec_helper.rb
281
+ - site_template/spec/support/phlex.rb
283
282
  - site_template/spec/views/pages/home_spec.rb
284
283
  - site_template/tailwind.config.js
285
284
  - site_template/vite.config.ts
@@ -291,7 +290,6 @@ metadata:
291
290
  source_code_uri: https://github.com/nolantait/staticky
292
291
  changelog_uri: https://github.com/nolantait/staticky
293
292
  rubygems_mfa_required: 'true'
294
- post_install_message:
295
293
  rdoc_options: []
296
294
  require_paths:
297
295
  - lib
@@ -306,8 +304,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
306
304
  - !ruby/object:Gem::Version
307
305
  version: '0'
308
306
  requirements: []
309
- rubygems_version: 3.5.22
310
- signing_key:
307
+ rubygems_version: 3.6.2
311
308
  specification_version: 4
312
309
  summary: Static site
313
310
  test_files: []
@@ -1 +0,0 @@
1
- 3.3.5
@@ -1,6 +0,0 @@
1
- export default {
2
- plugins: {
3
- tailwindcss: {},
4
- autoprefixer: {},
5
- },
6
- }