This commit is contained in:
24c02 2026-01-28 17:23:53 -05:00
parent b18c1db69b
commit 3d8b180b11
16 changed files with 217 additions and 73 deletions

View file

@ -61,3 +61,4 @@ gem "omniauth"
gem "omniauth-hack_club"
gem "faraday"
gem "pundit"
gem "primer_view_components"

View file

@ -198,6 +198,7 @@ GEM
rack (>= 1.2, < 4)
snaky_hash (~> 2.0, >= 2.0.3)
version_gem (~> 1.1, >= 1.1.9)
octicons (19.21.2)
omniauth (2.1.4)
hashie (>= 3.4.6)
logger
@ -229,6 +230,11 @@ GEM
pp (0.6.3)
prettyprint
prettyprint (0.2.0)
primer_view_components (0.49.0)
actionview (>= 7.2.0)
activesupport (>= 7.2.0)
octicons (>= 18.0.0)
view_component (>= 3.1, < 5.0)
prism (1.8.0)
propshaft (1.3.1)
actionpack (>= 7.0.0)
@ -380,6 +386,10 @@ GEM
uri (1.1.1)
useragent (0.16.11)
version_gem (1.1.9)
view_component (4.2.0)
actionview (>= 7.1.0)
activesupport (>= 7.1.0)
concurrent-ruby (~> 1)
vite_rails (3.0.20)
railties (>= 5.1, < 9)
vite_ruby (~> 3.0, >= 3.2.2)
@ -429,6 +439,7 @@ DEPENDENCIES
omniauth-hack_club
pg (~> 1.3)
phlex-rails
primer_view_components
propshaft
pry-rails
puma (>= 5.0)

View file

@ -0,0 +1,32 @@
# frozen_string_literal: true
class Components::HeaderBar < Components::Base
register_value_helper :signed_in?
register_value_helper :impersonating?
def view_template
header(class: "app-header", style: "display: flex; align-items: center; justify-content: space-between;") do
div(style: "display: flex; align-items: center; gap: 1rem;") do
span(class: "app-header-brand") do
plain "Hack Club CDN"
sup(class: "app-header-env-badge") { "(dev)" } if Rails.env.development?
end
end
return unless signed_in?
div(style: "display: flex; align-items: center; gap: 0.5rem;") do
render(Primer::Alpha::ActionMenu.new(anchor_align: :end)) do |menu|
menu.with_show_button(scheme: :invisible) do |btn|
btn.with_leading_visual_icon(icon: impersonating? ? :eye : :person)
plain current_user.name
end
menu.with_item(label: "Log out", href: logout_path, data: { method: :delete }) do |item|
item.with_leading_visual_icon(icon: :"sign-out")
end
end
end
end
end
end

View file

@ -1,7 +1,7 @@
class ApplicationController < ActionController::Base
before_action :require_authentication!
helper_method :current_user, :signed_in?
helper_method :current_user, :signed_in?, :impersonating?
private
@ -15,6 +15,8 @@ class ApplicationController < ActionController::Base
redirect_to login_path, alert: "Please sign in to continue." unless signed_in?
end
def impersonating? = false
include Pundit::Authorization
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

View file

@ -1,10 +1,6 @@
class StaticPagesController < ApplicationController
skip_before_action :require_authentication!, only: [:login]
skip_before_action :require_authentication!, only: [:home]
def home
end
def login
redirect_to home_path if signed_in?
end
end

View file

@ -1,28 +1 @@
// To see this message, add the following to the `<head>` section in your
// views/layouts/application.html.erb
//
// <%= vite_client_tag %>
// <%= vite_javascript_tag 'application' %>
console.log('Vite ⚡️ Rails')
// If using a TypeScript entrypoint file:
// <%= vite_typescript_tag 'application' %>
//
// If you want to use .jsx or .tsx, add the extension:
// <%= vite_javascript_tag 'application.jsx' %>
console.log('Visit the guide for more information: ', 'https://vite-ruby.netlify.app/guide/rails')
// Example: Load Rails libraries in Vite.
//
// import * as Turbo from '@hotwired/turbo'
// Turbo.start()
//
// import ActiveStorage from '@rails/activestorage'
// ActiveStorage.start()
//
// // Import all channels.
// const channels = import.meta.glob('./**/*_channel.js', { eager: true })
// Example: Import a stylesheet in app/frontend/index.css
// import '~/index.css'
import "@primer/view-components/app/components/primer/primer.js";

View file

@ -1,3 +1,21 @@
@use "@/styles/dark_mode";
@use '@primer/css/dist/primer.css';
@use '@primer/view-components/app/assets/styles/primer_view_components.css';
@use '@primer/primitives/dist/css/primitives.css';
@use '@primer/primitives/dist/css/functional/themes/light.css';
@use '@primer/primitives/dist/css/functional/themes/dark.css';
@use "@/styles/hca";@use "@/styles/admin_tool";
@use "@/styles/dark_mode";
@use "@/styles/hca";
@use "@/styles/admin_tool";
.app-header {
position: static;
top: 0;
z-index: 100;
display: flex;
align-items: center;
gap: var(--base-size-12, 12px);
padding: var(--base-size-12, 12px) var(--base-size-16, 16px);
background-color: var(--bgColor-default);
border-bottom: 1px solid var(--borderColor-muted);
}

View file

@ -1,3 +0,0 @@
html {
color-scheme: light dark;
}

View file

@ -1,25 +0,0 @@
.hca-button {
background: linear-gradient(to bottom, #ff4d64 0%, #ec3750 50%, #d42f45 100%);
color: #fff;
border: 1px solid #a82438;
border-radius: 6px;
padding: 0.7rem 1.4rem;
font-weight: 600;
cursor: pointer;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.25),
0 2px 3px rgba(0, 0, 0, 0.2);
transition: box-shadow 0.1s ease;
&:hover {
background: linear-gradient(to bottom, #ff5a6e 0%, #f04058 50%, #db3448 100%);
}
&:active {
background: linear-gradient(to bottom, #c92a3e 0%, #d42f45 50%, #ec3750 100%);
box-shadow:
inset 0 2px 4px rgba(0, 0, 0, 0.3),
0 1px 0 rgba(255, 255, 255, 0.1);
}
}

View file

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html data-color-mode="auto" data-light-theme="light" data-dark-theme="dark">
<head>
<title><%= content_for(:title) || "CDN" %></title>
<meta name="viewport" content="width=device-width,initial-scale=1">
@ -34,6 +34,7 @@
</head>
<body>
<%= render(Components::HeaderBar.new) %>
<%= yield %>
</body>
</html>

View file

@ -1,2 +1,5 @@
<h1>Home</h1>
<%= button_to "Logout", logout_path, method: :delete, data: { turbo: false } if signed_in? %>
<% if signed_in? %>
<% else %>
<%= button_to "Sign in with Hack Club", "/auth/hack_club", method: :post, class: "btn btn-primary btn-large", data: { turbo: false } %>
<% end %>

View file

@ -1,2 +0,0 @@
<h1>Login</h1>
<%= button_to 'Sign in with Hack Club', '/auth/hack_club', method: :post, class: "hca-button", data: { turbo: false } %>

View file

@ -8,6 +8,11 @@ Bundler.require(*Rails.groups)
module CDN
class Application < Rails::Application
require "view_component"
require "primer/view_components"
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 8.0

View file

@ -5,5 +5,10 @@
"sass-embedded": "^1.97.3",
"vite": "^6.0.0",
"vite-plugin-ruby": "5.1.1"
},
"dependencies": {
"@primer/css": "^22.1.0",
"@primer/primitives": "^11.3.2",
"@primer/view-components": "^0.49.0"
}
}

View file

@ -1,8 +1,20 @@
import { defineConfig } from 'vite'
import {defineConfig} from 'vite'
import RubyPlugin from 'vite-plugin-ruby'
export default defineConfig({
plugins: [
RubyPlugin(),
],
plugins: [
RubyPlugin(),
],
build: {
minify: false
},
server: {
hmr: {
overlay: true
}
},
})

115
yarn.lock
View file

@ -137,6 +137,75 @@
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz#9bdad8176be7811ad148d1f8772359041f46c6c5"
integrity sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==
"@github/auto-check-element@^6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@github/auto-check-element/-/auto-check-element-6.0.0.tgz#4baa1750599532c8ab79877c69ab677a0a5c411c"
integrity sha512-87mHEywJEtlG/37zFrx4PUgDqczgtv9jrauW3IojNy9y+nALIAm6e2jnWpfgcqeMWSevzph2M6reJoHpuSjyWw==
dependencies:
"@github/mini-throttle" "^2.1.0"
"@github/auto-complete-element@^3.8.0":
version "3.8.0"
resolved "https://registry.yarnpkg.com/@github/auto-complete-element/-/auto-complete-element-3.8.0.tgz#8be0480b8412ffb4fb71b54a68513c5e29693d86"
integrity sha512-rS2Uj38V1BsenLvrIswV5IXfiYH2/KUhz6inot+JXho/fFOO+01tsW1HxqSdIXqh5EDuoY0f/GQsztZcH22AXQ==
dependencies:
"@github/combobox-nav" "^2.1.7"
"@github/catalyst@^1.6.0":
version "1.7.0"
resolved "https://registry.yarnpkg.com/@github/catalyst/-/catalyst-1.7.0.tgz#12dd1097a66260f0dde1d1d1f5ebfe7d1f576a80"
integrity sha512-qOAxrDdRZz9+v4y2WoAfh11rpRY/x4FRofPNmJyZFzAjubtzE3sCa/tAycWWufmQGoYiwwzL/qJBBgyg7avxPw==
"@github/clipboard-copy-element@^1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@github/clipboard-copy-element/-/clipboard-copy-element-1.3.0.tgz#d518d2aadb677c5c9560a54d7fd4b0d3abf00a9b"
integrity sha512-wyntkQkwoLbLo+Hqg2LIVMXDIzcvUb9bSDz+clX6nVJItwzh103rHxdXFRZD+DmxVbuEW5xSznYQXkz1jZT+xg==
"@github/combobox-nav@^2.1.7":
version "2.3.1"
resolved "https://registry.yarnpkg.com/@github/combobox-nav/-/combobox-nav-2.3.1.tgz#76da4c47f1e33af56392c5c9cf661a28d5b4168e"
integrity sha512-gwxPzLw8XKecy1nP63i9lOBritS3bWmxl02UX6G0TwMQZbMem1BCS1tEZgYd3mkrkiDrUMWaX+DbFCuDFo3K+A==
"@github/details-menu-element@^1.0.12":
version "1.0.13"
resolved "https://registry.yarnpkg.com/@github/details-menu-element/-/details-menu-element-1.0.13.tgz#d62263077b16bc7edc386e7b23f0ce41af1301b4"
integrity sha512-gMkii86w/oUP5dq8yOWZn1sgbgtFj3AYETxxtpsqRggZktgd8te4+npAn4Hm+936c/lxmEzXqfjARL/CzGR4+w==
"@github/image-crop-element@^5.0.0":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@github/image-crop-element/-/image-crop-element-5.0.0.tgz#6ae2c31f1e7dc355c41c3140554fb76ca7a71ef7"
integrity sha512-Vgm2OwWAs1ESoib/t5sjxsAYo6YTOxxAjWDRxswX7qrqoyCejTZ3hshdo4Ep5e+Mz/GVTZC3rdMtg06dk/eT4g==
"@github/include-fragment-element@^6.3.0":
version "6.4.1"
resolved "https://registry.yarnpkg.com/@github/include-fragment-element/-/include-fragment-element-6.4.1.tgz#fb20bfa9b0655a5d894fd40ec5faafcddc8db80c"
integrity sha512-ffgXc7qwBtY/rYcMkAjxZJlyOPFaeC9K1Oc+n7Edwt3BAHPokUSdMfDivb+/dGO+NU2n7l1/L4v5uQN+wBeV4g==
"@github/mini-throttle@^2.1.0":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@github/mini-throttle/-/mini-throttle-2.1.1.tgz#c66db5c3b857aaf8c467de2528cd92f36f542ac5"
integrity sha512-KtOPaB+FiKJ6jcKm9UKyaM5fPURHGf+xcp+b4Mzoi81hOc6M1sIGpMZMAVbNzfa2lW5+RPGKq888Px0j76OZ/A==
"@github/relative-time-element@^4.0.0":
version "4.5.1"
resolved "https://registry.yarnpkg.com/@github/relative-time-element/-/relative-time-element-4.5.1.tgz#66a9ba300b03982950d75f417f3f2ad27236bffb"
integrity sha512-uxCxCwe9vdwUDmRmM84tN0UERlj8MosLV44+r/VDj7DZUVUSTP4vyWlE9mRK6vHelOmT8DS3RMlaMrLlg1h1PQ==
"@github/remote-input-element@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@github/remote-input-element/-/remote-input-element-0.4.0.tgz#76956e82342d5887b68f3fe7ce8c20ff1f55181b"
integrity sha512-apsMwsFW24F+w2wzT8oKoBi9lpm6GeFOmtuL+1YwDVmIiwixfHOD3MnEsEOv0RwmHsMdWmIjP9mxWyTWPKZHGg==
"@github/tab-container-element@^3.1.2":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@github/tab-container-element/-/tab-container-element-3.4.0.tgz#0a167ed81c9f4a1c1c79f0d0a6a8c012c49a6147"
integrity sha512-Yx70pO8A0p7Stnm9knKkUNX8i4bjuwDYZarRkM8JH0Z+ffhpe++oNAPbzGI9GEcGugRHvKuSC6p4YOdoHtTniQ==
"@lit-labs/ssr-dom-shim@^1.2.1":
version "1.5.1"
resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.5.1.tgz#3166900c0d481f03d6d4133686e0febf760d521d"
integrity sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@ -158,6 +227,11 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@oddbird/popover-polyfill@^0.5.2":
version "0.5.2"
resolved "https://registry.yarnpkg.com/@oddbird/popover-polyfill/-/popover-polyfill-0.5.2.tgz#9a142cae54b6e48824bec61e94e39541c9746b69"
integrity sha512-iFrvar5SOMtKFOSjYvs4z9UlLqDdJbMx0mgISLcPedv+g0ac5sgeETLGtipHCVIae6HJPclNEH5aCyD1RZaEHw==
"@parcel/watcher-android-arm64@2.5.6":
version "2.5.6"
resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz#5f32e0dba356f4ac9a11068d2a5c134ca3ba6564"
@ -247,6 +321,47 @@
"@parcel/watcher-win32-ia32" "2.5.6"
"@parcel/watcher-win32-x64" "2.5.6"
"@primer/behaviors@^1.3.4":
version "1.10.0"
resolved "https://registry.yarnpkg.com/@primer/behaviors/-/behaviors-1.10.0.tgz#9b4f52315b7d00c8afd2c5db2c56fe02d92660e9"
integrity sha512-+GaAqCJuoYVf0Sy67mJfhw7k17nrCnfanI4H6NFEyToDC1ghrOC9Yl7627WTWpqGg+1lPhjF7OHF7VClLz52oA==
"@primer/css@^22.1.0":
version "22.1.0"
resolved "https://registry.yarnpkg.com/@primer/css/-/css-22.1.0.tgz#b85af5cf9c18b3f9e4aa298699e9137964c87687"
integrity sha512-Nwg9QaRiBeu0BU6h+Su0X07daihX1obiuqGRG8y+SexOnvWhN2J5n4OFAvGfQsit07Y7Q6gGoK+yVU5tb8CtDA==
"@primer/live-region-element@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@primer/live-region-element/-/live-region-element-0.8.0.tgz#79f8a5824a7762d26eb86789962de54e5c295dee"
integrity sha512-DIp04IeZvZ+gwCUcBchIvRwJA2PikP/6hnFhcLKgwttcg5OYjBH9t0cZjLnv10Aq1jN0rAFFG+WPMd3bw4hXcA==
dependencies:
"@lit-labs/ssr-dom-shim" "^1.2.1"
"@primer/primitives@^11.3.2":
version "11.3.2"
resolved "https://registry.yarnpkg.com/@primer/primitives/-/primitives-11.3.2.tgz#2ea09ef48b7db9e66f3406553f453d8bdd665b34"
integrity sha512-/8EDh3MmF9cbmrLETFmIuNFIdvpSCkvBlx6zzD8AZ4dZ5UYExQzFj8QAtIrRtCFJ2ZmW5QrtrPR3+JVb8KEDpg==
"@primer/view-components@^0.49.0":
version "0.49.0"
resolved "https://registry.yarnpkg.com/@primer/view-components/-/view-components-0.49.0.tgz#8b913ba790f92f4a55f46f1391d2700e2842c187"
integrity sha512-6JTIxvdofczvXDG82OjXzsumTqzC5UIU7EXQ79G4O2nEAxDreZ45x39jj3BHj+4wiO7BCdYCe9YsuD3AyvDPzQ==
dependencies:
"@github/auto-check-element" "^6.0.0"
"@github/auto-complete-element" "^3.8.0"
"@github/catalyst" "^1.6.0"
"@github/clipboard-copy-element" "^1.3.0"
"@github/details-menu-element" "^1.0.12"
"@github/image-crop-element" "^5.0.0"
"@github/include-fragment-element" "^6.3.0"
"@github/relative-time-element" "^4.0.0"
"@github/remote-input-element" "^0.4.0"
"@github/tab-container-element" "^3.1.2"
"@oddbird/popover-polyfill" "^0.5.2"
"@primer/behaviors" "^1.3.4"
"@primer/live-region-element" "^0.8.0"
"@rollup/rollup-android-arm-eabi@4.57.0":
version "4.57.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.0.tgz#f762035679a6b168138c94c960fda0b0cdb00d98"