diff --git a/app/controllers/api/v1/briefings_controller.rb b/app/controllers/api/v1/briefings_controller.rb index 70fe429..e12f106 100644 --- a/app/controllers/api/v1/briefings_controller.rb +++ b/app/controllers/api/v1/briefings_controller.rb @@ -1,8 +1,6 @@ module Api module V1 - class BriefingsController < ApplicationController - skip_before_action :verify_authenticity_token - + class BriefingsController < BaseController RECIPIENT = "austindanielfrench@gmail.com".freeze def send_briefing diff --git a/app/controllers/concerns/http_basic_authenticable.rb b/app/controllers/concerns/http_basic_authenticable.rb deleted file mode 100644 index f573e4f..0000000 --- a/app/controllers/concerns/http_basic_authenticable.rb +++ /dev/null @@ -1,23 +0,0 @@ -module HttpBasicAuthenticable - extend ActiveSupport::Concern - - included do - before_action :authenticate_admin!, if: :admin_authentication_required? - end - - private - - def authenticate_admin! - authenticate_or_request_with_http_basic("Admin Area") do |username, password| - expected_username = ENV.fetch("ADMIN_USER_NAME", "admin") - expected_password = ENV.fetch("ADMIN_PASSWORD", "changeme123") - - ActiveSupport::SecurityUtils.secure_compare(username, expected_username) && - ActiveSupport::SecurityUtils.secure_compare(password, expected_password) - end - end - - def admin_authentication_required? - true - end -end diff --git a/app/helpers/invoices_helper.rb b/app/helpers/invoices_helper.rb index ebb749d..061b28d 100644 --- a/app/helpers/invoices_helper.rb +++ b/app/helpers/invoices_helper.rb @@ -1,15 +1,5 @@ module InvoicesHelper - def format_money(cents) - return "$0.00" if cents.nil? || cents == 0 - dollars = cents.to_f / 100 - negative = dollars < 0 - dollars = dollars.abs - formatted = format("%.2f", dollars) - parts = formatted.split(".") - parts[0] = parts[0].gsub(/(\d)(?=(\d{3})+(?!\d))/, '\\1,') - result = "$#{parts.join('.')}" - negative ? "-#{result}" : result - end + include MoneyFormattable def invoice_status_badge(status) colors = { diff --git a/app/javascript/components/ScrollbarStyles.jsx b/app/javascript/components/ScrollbarStyles.jsx deleted file mode 100644 index 733c913..0000000 --- a/app/javascript/components/ScrollbarStyles.jsx +++ /dev/null @@ -1,53 +0,0 @@ -import React, { useEffect } from 'react'; - -const ScrollbarStyles = () => { - useEffect(() => { - // Create and append a style element to ensure scrollbar styles are applied with high priority - const styleEl = document.createElement('style'); - styleEl.textContent = ` - /* Custom Timeline Scrollbar (Applied via JS for higher priority) */ - ::-webkit-scrollbar { - width: 8px !important; - } - - ::-webkit-scrollbar-track { - background-color: #f1f1f1 !important; - background-image: linear-gradient( - to bottom, - transparent 0px, - transparent 98px, - #aaa 98px, - #aaa 102px, - transparent 102px - ) !important; - background-repeat: repeat-y !important; - background-position: center !important; - background-size: 2px auto !important; - } - - ::-webkit-scrollbar-thumb { - background: #888 !important; - border-radius: 4px !important; - } - - ::-webkit-scrollbar-thumb:hover { - background: #555 !important; - } - - /* Firefox */ - * { - scrollbar-width: thin !important; - scrollbar-color: #888 #f1f1f1 !important; - } - `; - document.head.appendChild(styleEl); - - return () => { - document.head.removeChild(styleEl); - }; - }, []); - - return null; // This component doesn't render anything -}; - -export default ScrollbarStyles; \ No newline at end of file diff --git a/app/javascript/components/markdown/DebugPanel.jsx b/app/javascript/components/markdown/DebugPanel.jsx deleted file mode 100644 index aa02761..0000000 --- a/app/javascript/components/markdown/DebugPanel.jsx +++ /dev/null @@ -1,26 +0,0 @@ -// File: app/javascript/components/markdown/DebugPanel.jsx -import React from 'react'; - -const DebugPanel = ({ slug, useElementId, content }) => { - if (!content) return null; - - return ( -
-

Debug Info:

-

Slug: {slug || 'No slug provided'}

-

Using element ID: {useElementId || 'None'}

-

Content length: {content ? content.length : 0} characters

-

Content preview: {content ? content.substring(0, 50) + '...' : 'None'}

-
- ); -}; - -export default DebugPanel; \ No newline at end of file diff --git a/app/models/concerns/money_formattable.rb b/app/models/concerns/money_formattable.rb new file mode 100644 index 0000000..32815ba --- /dev/null +++ b/app/models/concerns/money_formattable.rb @@ -0,0 +1,15 @@ +module MoneyFormattable + extend ActiveSupport::Concern + + def format_money(cents) + return "$0.00" if cents.nil? || cents == 0 + dollars = cents.to_f / 100 + negative = dollars < 0 + dollars = dollars.abs + formatted = format("%.2f", dollars) + parts = formatted.split(".") + parts[0] = parts[0].gsub(/(\d)(?=(\d{3})+(?!\d))/, '\\1,') + result = "$#{parts.join('.')}" + negative ? "-#{result}" : result + end +end diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 7854240..fee1df9 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -1,4 +1,6 @@ class Invoice < ApplicationRecord + include MoneyFormattable + belongs_to :client has_many :line_items, class_name: "InvoiceLineItem", dependent: :destroy @@ -65,15 +67,4 @@ def calculate_totals self.tax_cents = (subtotal_cents * (tax_rate || 0) / 100).round self.total_cents = subtotal_cents + tax_cents end - - def format_money(cents) - dollars = cents.to_f / 100 - "$#{number_with_delimiter(format('%.2f', dollars))}" - end - - def number_with_delimiter(number) - parts = number.to_s.split(".") - parts[0] = parts[0].gsub(/(\d)(?=(\d{3})+(?!\d))/, '\\1,') - parts.join(".") - end end diff --git a/app/services/invoice_pdf_service.rb b/app/services/invoice_pdf_service.rb index 9fb932c..e497fcd 100644 --- a/app/services/invoice_pdf_service.rb +++ b/app/services/invoice_pdf_service.rb @@ -1,4 +1,6 @@ class InvoicePdfService + include MoneyFormattable + ACCENT_COLOR = "1DB954" def initialize(invoice) @@ -198,13 +200,4 @@ def draw_footer(pdf) end pdf.fill_color "000000" end - - def format_money(cents) - return "$0.00" if cents.nil? || cents == 0 - dollars = cents.to_f / 100 - formatted = format("%.2f", dollars) - parts = formatted.split(".") - parts[0] = parts[0].gsub(/(\d)(?=(\d{3})+(?!\d))/, '\\1,') - "$#{parts.join('.')}" - end end diff --git a/app/views/pwa/manifest.json.erb b/app/views/pwa/manifest.json.erb deleted file mode 100644 index 0beb359..0000000 --- a/app/views/pwa/manifest.json.erb +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "Austn", - "icons": [ - { - "src": "/icon.png", - "type": "image/png", - "sizes": "512x512" - }, - { - "src": "/icon.png", - "type": "image/png", - "sizes": "512x512", - "purpose": "maskable" - } - ], - "start_url": "/", - "display": "standalone", - "scope": "/", - "description": "Austn.", - "theme_color": "red", - "background_color": "red" -} diff --git a/app/views/pwa/service-worker.js b/app/views/pwa/service-worker.js deleted file mode 100644 index b3a13fb..0000000 --- a/app/views/pwa/service-worker.js +++ /dev/null @@ -1,26 +0,0 @@ -// Add a service worker for processing Web Push notifications: -// -// self.addEventListener("push", async (event) => { -// const { title, options } = await event.data.json() -// event.waitUntil(self.registration.showNotification(title, options)) -// }) -// -// self.addEventListener("notificationclick", function(event) { -// event.notification.close() -// event.waitUntil( -// clients.matchAll({ type: "window" }).then((clientList) => { -// for (let i = 0; i < clientList.length; i++) { -// let client = clientList[i] -// let clientPath = (new URL(client.url)).pathname -// -// if (clientPath == event.notification.data.path && "focus" in client) { -// return client.focus() -// } -// } -// -// if (clients.openWindow) { -// return clients.openWindow(event.notification.data.path) -// } -// }) -// ) -// }) diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb deleted file mode 100644 index b3076b3..0000000 --- a/config/initializers/content_security_policy.rb +++ /dev/null @@ -1,25 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Define an application-wide content security policy. -# See the Securing Rails Applications Guide for more information: -# https://guides.rubyonrails.org/security.html#content-security-policy-header - -# Rails.application.configure do -# config.content_security_policy do |policy| -# policy.default_src :self, :https -# policy.font_src :self, :https, :data -# policy.img_src :self, :https, :data -# policy.object_src :none -# policy.script_src :self, :https -# policy.style_src :self, :https -# # Specify URI for violation reports -# # policy.report_uri "/csp-violation-report-endpoint" -# end -# -# # Generate session nonces for permitted importmap, inline scripts, and inline styles. -# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } -# config.content_security_policy_nonce_directives = %w(script-src style-src) -# -# # Report violations without enforcing the policy. -# # config.content_security_policy_report_only = true -# end diff --git a/config/initializers/react_server_rendering.rb b/config/initializers/react_server_rendering.rb deleted file mode 100644 index f9247bb..0000000 --- a/config/initializers/react_server_rendering.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -# To render React components in production, precompile the server rendering manifest: -Rails.application.config.assets.precompile += [ "server_rendering.js" ] diff --git a/config/routes.rb b/config/routes.rb index 7b7f0d0..fbe41e7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -57,8 +57,6 @@ # Claude Corner get "/claude", to: "claude_corner#index" - # Movement demo - get "/movement-demo", to: "movement_demo#index" # Pitch checker get "/pitch", to: "pitch#index" diff --git a/lib/tasks/blog.rake b/lib/tasks/blog.rake deleted file mode 100644 index 347f422..0000000 --- a/lib/tasks/blog.rake +++ /dev/null @@ -1,6 +0,0 @@ -namespace :blog do - desc "Import markdown files from Obsidian public notes directory" - task import_obsidian_notes: :environment do - ImportObsidianNotesJob.perform_now - end -end diff --git a/lib/tasks/convert_images.rake b/lib/tasks/convert_images.rake deleted file mode 100644 index 1789c28..0000000 --- a/lib/tasks/convert_images.rake +++ /dev/null @@ -1,153 +0,0 @@ -namespace :images do - desc "Convert game textures to WebP format for better performance" - task convert_to_webp: :environment do - require "fileutils" - - # Check if cwebp command is available - unless system("which cwebp > /dev/null 2>&1") - puts "Error: cwebp utility not found. Please install it first:" - puts " macOS: brew install webp" - puts " Ubuntu/Debian: sudo apt-get install webp" - puts " Windows: Download from https://developers.google.com/speed/webp/download" - exit 1 - end - - # Define directories to process - dirs_to_process = [ - Rails.root.join("public", "assets", "textures") - ] - - total_converted = 0 - total_savings = 0 - - dirs_to_process.each do |dir| - next unless Dir.exist?(dir) - - # Get all image files recursively - images = Dir.glob("#{dir}/**/*.{jpg,jpeg,png}") - - images.each do |image_path| - original_size = File.size(image_path) - output_path = "#{image_path.chomp(File.extname(image_path))}.webp" - - # Skip if WebP version already exists and is newer - if File.exist?(output_path) && File.mtime(output_path) >= File.mtime(image_path) - puts "Skipping #{image_path} (WebP already exists and is up-to-date)" - next - end - - # Determine quality based on file type - quality = image_path.end_with?(".png") ? 90 : 85 - - # Convert image to WebP - success = system("cwebp -q #{quality} \"#{image_path}\" -o \"#{output_path}\"") - - if success - webp_size = File.size(output_path) - savings = ((original_size - webp_size) / original_size.to_f * 100).round(2) - total_savings += original_size - webp_size - - puts "Converted #{image_path} to WebP, saved #{savings}% (#{original_size} → #{webp_size} bytes)" - total_converted += 1 - else - puts "Failed to convert #{image_path}" - end - end - end - - if total_converted > 0 - total_savings_mb = (total_savings / 1024.0 / 1024.0).round(2) - puts "\nConverted #{total_converted} images, total savings: #{total_savings_mb} MB" - else - puts "\nNo images were converted." - end - end - - desc "Resize and optimize all images" - task optimize: :environment do - require "fileutils" - - # Check for required tools - %w[convert identify].each do |cmd| - unless system("which #{cmd} > /dev/null 2>&1") - puts "Error: #{cmd} command not found. Please install ImageMagick:" - puts " macOS: brew install imagemagick" - puts " Ubuntu/Debian: sudo apt-get install imagemagick" - exit 1 - end - end - - # Define size limits for different image types - MAX_GAME_TEXTURE_SIZE = 1024 # Maximum texture dimension for game - MAX_THUMBNAIL_SIZE = 480 # Maximum thumbnail dimension - MAX_PROFILE_PIC_SIZE = 256 # Maximum profile picture dimension - - # Define directories to process - dirs_to_process = [ - Rails.root.join("public", "assets", "textures") - ] - - total_processed = 0 - total_savings = 0 - - dirs_to_process.each do |dir| - next unless Dir.exist?(dir) - - # Get all image files recursively - images = Dir.glob("#{dir}/**/*.{jpg,jpeg,png}") - - images.each do |image_path| - original_size = File.size(image_path) - - # Skip small files (less than 10KB) - next if original_size < 10 * 1024 - - # Get image dimensions - dimensions = `identify -format "%wx%h" "#{image_path}"`.strip.split("x").map(&:to_i) - width, height = dimensions - - # Determine max size based on image type/location - max_size = MAX_GAME_TEXTURE_SIZE - - # Calculate new dimensions (only if image is larger than max size) - if width > max_size || height > max_size - if width > height - new_width = max_size - new_height = (height.to_f / width * max_size).to_i - else - new_height = max_size - new_width = (width.to_f / height * max_size).to_i - end - - # Create a temporary file path - temp_path = "#{image_path}.tmp" - - # Resize and optimize the image - success = system("convert \"#{image_path}\" -resize #{new_width}x#{new_height} -strip -quality 85 \"#{temp_path}\"") - - if success - # Replace the original with the optimized version - FileUtils.mv(temp_path, image_path) - - new_size = File.size(image_path) - savings = ((original_size - new_size) / original_size.to_f * 100).round(2) - total_savings += original_size - new_size - - puts "Resized #{image_path} from #{width}x#{height} to #{new_width}x#{new_height}, saved #{savings}% (#{original_size} → #{new_size} bytes)" - total_processed += 1 - else - puts "Failed to optimize #{image_path}" - FileUtils.rm(temp_path) if File.exist?(temp_path) - end - end - end - end - - if total_processed > 0 - total_savings_mb = (total_savings / 1024.0 / 1024.0).round(2) - puts "\nOptimized #{total_processed} images, total savings: #{total_savings_mb} MB" - else - puts "\nNo images were optimized." - end - end -end diff --git a/test/controllers/movement_demo_controller_test.rb b/test/controllers/movement_demo_controller_test.rb deleted file mode 100644 index f7230c5..0000000 --- a/test/controllers/movement_demo_controller_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class MovementDemoControllerTest < ActionDispatch::IntegrationTest - # test "the truth" do - # assert true - # end -end