chore: init commit

in worker.../repo/GITFOLDER.zip is the .git folder.
This commit is contained in:
2026-08-11 14:44:09 -04:00
parent 0012380fd3
commit 2854619bc9
782 changed files with 65944 additions and 0 deletions

View File

@@ -0,0 +1,170 @@
<!-- Hidden checkbox for menu toggle (CSS-only, no JavaScript!) -->
<input type="checkbox" id="mobile-menu-toggle" class="hidden peer">
<!-- Overlay - shows when checkbox is checked -->
<label
for="mobile-menu-toggle"
class="fixed inset-0 bg-black/50 z-40 hidden peer-checked:block lg:hidden"></label>
<!-- Sidebar - slides in when checkbox is checked -->
<nav class="fixed z-50 top-0 bottom-0 left-0 w-64
transform -translate-x-full peer-checked:translate-x-0
lg:translate-x-0 lg:top-16 lg:w-50
transition-transform duration-300 ease-in-out">
<div class="flex flex-col h-full overflow-y-auto px-0 pt-16 lg:pt-4 pb-4 bg-[#00698c]">
<!-- Close button (mobile only) -->
<label
for="mobile-menu-toggle"
class="lg:hidden absolute top-4 right-4
flex items-center justify-center w-10 h-10
text-white hover:bg-white/10 rounded-lg
cursor-pointer transition-colors">
<!-- X icon -->
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</label>
<nav class="flex flex-1 flex-col">
<ul role="list" class="flex flex-1 flex-col gap-y-1 px-3">
<li>
<ul role="list" class="space-y-1">
<!-- Home link -->
<li>
<% is_active = request.path == root_path %>
<label for="mobile-menu-toggle" class="lg:cursor-default cursor-pointer">
<%= link_to root_path, class: "flex items-center justify-start px-3 py-3 rounded-lg w-full group hover:bg-black/20 #{'bg-[#d3df44]' if is_active}", style: is_active ? "background-color: #d3df44;" : "" do %>
<div class="flex gap-3 items-center">
<div class="w-6 h-6">
<%= image_tag "house.svg", class: "w-6 h-6", style: "filter: brightness(0) saturate(100%) #{is_active ? 'invert(20%) sepia(8%) saturate(348%) hue-rotate(114deg) brightness(98%) contrast(85%)' : 'invert(93%) sepia(13%) saturate(343%) hue-rotate(31deg) brightness(115%) contrast(90%)'};" %>
</div>
<span class="font-medium text-sm" style="color: <%= is_active ? '#323232' : 'white' %>; font-family: Inter, sans-serif;">Home</span>
</div>
<% end %>
</label>
</li>
<!-- Portfolio link -->
<% if current_user.portfolio && policy(current_user.portfolio).show? %>
<li>
<% is_active = request.path.include?('portfolios') %>
<label for="mobile-menu-toggle" class="lg:cursor-default cursor-pointer">
<%= link_to user_portfolio_path(current_user, current_user.portfolio), class: "flex items-center justify-start px-3 py-3 rounded-lg w-full group hover:bg-black/20 #{'bg-[#d3df44]' if is_active}", style: is_active ? "background-color: #d3df44;" : "" do %>
<div class="flex gap-3 items-center">
<div class="w-6 h-6">
<%= image_tag "id-card.svg", class: "w-6 h-6", style: "filter: brightness(0) saturate(100%) #{is_active ? 'invert(20%) sepia(8%) saturate(348%) hue-rotate(114deg) brightness(98%) contrast(85%)' : 'invert(93%) sepia(13%) saturate(343%) hue-rotate(31deg) brightness(115%) contrast(90%)'};" %>
</div>
<span class="font-medium text-sm" style="color: <%= is_active ? '#323232' : 'white' %>; font-family: Inter, sans-serif;">My Portfolio</span>
</div>
<% end %>
</label>
</li>
<% end %>
<!-- Transactions link -->
<li>
<% is_active = request.path.include?('orders') %>
<label for="mobile-menu-toggle" class="lg:cursor-default cursor-pointer">
<%= link_to orders_path, class: "flex items-center justify-start px-3 py-3 rounded-lg w-full group hover:bg-black/20", style: is_active ? "background-color: #d3df44;" : "" do %>
<div class="flex gap-3 items-center">
<div class="w-6 h-6">
<%= image_tag "receipt.svg", class: "w-6 h-6", style: "filter: brightness(0) saturate(100%) #{is_active ? 'invert(20%) sepia(8%) saturate(348%) hue-rotate(114deg) brightness(98%) contrast(85%)' : 'invert(100%)'}" %>
</div>
<span class="font-medium text-sm" style="color: <%= is_active ? '#323232' : 'white' %>; font-family: Inter, sans-serif;">Transactions</span>
</div>
<% end %>
</label>
</li>
<!-- Classes link -->
<% if policy(Classroom).index? %>
<li>
<% is_active = request.path.include?('classrooms') && request.path.exclude?('admin') %>
<label for="mobile-menu-toggle" class="lg:cursor-default cursor-pointer">
<%= link_to classrooms_path, class: "flex items-center justify-start px-3 py-3 rounded-lg w-full group hover:bg-black/20", style: is_active ? "background-color: #d3df44;" : "" do %>
<div class="flex gap-3 items-center">
<div class="w-6 h-6">
<svg class="w-6 h-6" style="color: <%= is_active ? '#323232' : 'white' %>;" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z" />
</svg>
</div>
<span class="font-medium text-sm" style="color: <%= is_active ? '#323232' : 'white' %>; font-family: Inter, sans-serif;">Classes</span>
</div>
<% end %>
</label>
</li>
<% end %>
<!-- Trading Floor with collapsible stocks -->
<li>
<details <%= 'open' if request.path.include?('stocks') %> data-controller="stock-navbar-toggle">
<summary class="flex items-center justify-between px-3 py-3 rounded-lg w-full list-none cursor-pointer <%= 'bg-[#d3df44]' if request.path.include?('stocks') %>" style="<%= request.path.include?('stocks') ? 'background-color: #d3df44;' : '' %>">
<% is_active = request.path.include?('stocks') %>
<%= link_to stocks_path, class: "flex gap-3 items-center flex-1 hover:opacity-80", data: { action: "click->stock-navbar-toggle#navigateLink" } do %>
<div class="w-6 h-6">
<%= image_tag "chart-no-axes-combined.svg", class: "w-6 h-6", style: "filter: brightness(0) saturate(100%) #{is_active ? 'invert(20%) sepia(8%) saturate(348%) hue-rotate(114deg) brightness(98%) contrast(85%)' : 'invert(100%)'}" %>
</div>
<span class="font-medium text-sm" style="color: <%= is_active ? '#323232' : 'white' %>; font-family: Inter, sans-serif;">Trading Floor</span>
<% end %>
<div class="w-4 h-4 flex items-center justify-center cursor-pointer hover:opacity-70" data-action="click->stock-navbar-toggle#toggleChevron">
<i class="fa-solid fa-angle-down icon-down" style="color: <%= is_active ? '#323232' : 'white' %>;"></i>
<i class="fa-solid fa-angle-up icon-up" style="color: <%= is_active ? '#323232' : 'white' %>;"></i>
</div>
</summary>
<div class="box-border content-stretch flex flex-col items-start justify-start p-2 ml-6">
<% stocks.each do |stock| %>
<div class="content-stretch flex items-center justify-start relative rounded-2xl w-full">
<% stock_active = request.path == stock_path(stock) %>
<label for="mobile-menu-toggle" class="lg:cursor-default cursor-pointer w-full">
<%= link_to stock_path(stock), class: "flex gap-2 grow min-h-[44px] items-center justify-start px-3 py-2 rounded-2xl hover:bg-black/20 w-full" do %>
<div class="font-['Geist',sans-serif] font-normal text-sm text-white <%= 'underline decoration-2 underline-offset-2' if stock_active %>">
<p class="leading-none"><%= stock.ticker %></p>
</div>
<% end %>
</label>
</div>
<% end %>
</div>
</details>
</li>
</ul>
</li>
</ul>
</nav>
<!-- Bottom section (Admin, Logout) -->
<div class="flex flex-col items-center justify-start w-full mt-auto">
<div class="h-px w-full bg-[#004f6b]"></div>
<div class="flex flex-col items-start justify-start w-full py-2">
<% if policy(Classroom).new? %>
<% is_active = request.path.include?('admin') %>
<label for="mobile-menu-toggle" class="lg:cursor-default cursor-pointer w-full">
<%= link_to admin_classrooms_path, class: "flex items-center gap-x-4 px-6 py-3 text-sm font-semibold hover:bg-black/20 w-full", style: is_active ? "background-color: #d3df44;" : "" do %>
<svg class="w-5 h-5" style="color: <%= is_active ? '#323232' : 'white' %>;" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a6.759 6.759 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
</svg>
<span style="color: <%= is_active ? '#323232' : 'white' %>; font-family: Inter, sans-serif;">Admin</span>
<% end %>
</label>
<% end %>
<label for="mobile-menu-toggle" class="lg:cursor-default cursor-pointer w-full">
<%= link_to destroy_user_session_path, data: { turbo_method: :delete }, class: "flex items-center gap-x-4 px-6 py-3 text-sm font-semibold hover:bg-black/20 w-full" do %>
<svg class="w-5 h-5 text-white" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0 0 13.5 3h-6a2.25 2.25 0 0 0-2.25 2.25v13.5A2.25 2.25 0 0 0 7.5 21h6a2.25 2.25 0 0 0 2.25-2.25V15M12 9l-3 3m0 0 3 3m-3-3h12.75" />
</svg>
<span class="text-white" style="font-family: Inter, sans-serif;">Logout</span>
<% end %>
</label>
</div>
</div>
</div>
</nav>

View File

@@ -0,0 +1,13 @@
<div class="ticker-item">
<div class="text-lg font-bold <%= stock.percentage_change >= 0 ? 'text-green-up' : 'text-destructive' %>">
<%= stock.ticker.upcase %>
</div>
<div class="flex items-center justify-center gap-1 text-xs <%= stock.percentage_change >= 0 ? 'text-green-up' : 'text-destructive' %>">
<% if stock.percentage_change >= 0 %>
<%= lucide_icon("trending-up", class: "w-3 h-3") %>
<% else %>
<%= lucide_icon("trending-down", class: "w-3 h-3") %>
<% end %>
<%= stock.percentage_change_formatted %>
</div>
</div>

View File

@@ -0,0 +1,12 @@
<div class="flex-shrink-0 overflow-hidden" style="width: 400px;">
<div class="ticker-container">
<div class="ticker-content animate-scroll">
<%# Duplicate stocks for seamless infinite scroll: animation moves from 0% to -50%,
so when it reaches -50% (showing second copy), it loops back to 0% (first copy)
creating smooth continuous scrolling without gaps or visible restarts %>
<% (ticker_stocks.to_a * 2).each do |stock| %>
<%= render 'layouts/stock_item', stock: stock %>
<% end %>
</div>
</div>
</div>

View File

@@ -0,0 +1,3 @@
<div class="trix-content">
<%= yield -%>
</div>

View File

@@ -0,0 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<title>Admin - StocksInTheFuture</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag :app, 'data-turbo-track': "reload" %>
<%= stylesheet_link_tag "actiontext", 'data-turbo-track': "reload" %>
<%= javascript_importmap_tags %>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body class="min-h-screen bg-gray-50" data-controller="admin-sidebar">
<!-- Admin Header -->
<div class="fixed top-0 left-0 w-full z-50 bg-white border-b border-gray-200">
<div class="flex items-center justify-between py-3 px-6 h-16">
<div class="flex items-center gap-4">
<button
type="button"
data-action="click->admin-sidebar#toggle"
class="lg:hidden inline-flex items-center justify-center w-10 h-10 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
aria-label="Toggle menu">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
<h1 class="text-xl font-semibold text-gray-900">
<%= link_to admin_root_path do %>
<i class="fas fa-tools text-blue-600 mr-2"></i>
Admin Dashboard
<% end %>
</h1>
</div>
<div class="flex items-center gap-4">
<span class="hidden sm:inline text-sm text-gray-600">
<%= current_user.email %>
</span>
<%= link_to "View Site", root_path, class: "text-sm text-blue-600 hover:text-blue-800" %>
<%= link_to "Sign Out", destroy_user_session_path, data: { turbo_method: :delete }, class: "text-sm text-red-600 hover:text-red-800" %>
</div>
</div>
</div>
<!-- Admin Sidebar Navigation -->
<div class="fixed top-16 left-0 h-[calc(100vh-4rem)] w-64 bg-white border-r border-gray-200 overflow-y-auto lg:block hidden" id="admin-sidebar">
<nav class="p-4">
<%= render "admin/shared/navigation" %>
</nav>
</div>
<!-- Mobile Sidebar Overlay -->
<div class="fixed inset-0 bg-black bg-opacity-50 z-40 hidden"
data-admin-sidebar-target="overlay"
data-action="click->admin-sidebar#toggle"
style="display: none;"></div>
<!-- Mobile Sidebar -->
<div class="fixed top-16 left-0 h-[calc(100vh-4rem)] w-64 bg-white border-r border-gray-200 overflow-y-auto z-50 transform -translate-x-full transition-transform duration-300 lg:hidden"
data-admin-sidebar-target="mobileSidebar">
<nav class="p-4">
<%= render "admin/shared/navigation" %>
</nav>
</div>
<!-- Main Content -->
<main class="pt-16 lg:pl-64 min-h-screen">
<div class="p-6">
<!-- Flash Messages -->
<% if notice.present? %>
<p class="mb-4 p-4 bg-green-50 border border-green-200 text-green-800 rounded-lg" id="notice"><%= notice %></p>
<% end %>
<% if alert.present? %>
<p class="mb-4 p-4 bg-red-50 border border-red-200 text-red-800 rounded-lg" id="alert"><%= alert %></p>
<% end %>
<%= yield %>
</div>
</main>
</body>
</html>

View File

@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html>
<head>
<title>StocksInTheFuture</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag :app, 'data-turbo-track': "reload" %>
<%= stylesheet_link_tag "actiontext", 'data-turbo-track': "reload" %>
<%= javascript_importmap_tags %>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body class="min-h-screen bg-[#f7f9f3]">
<% if user_signed_in? %>
<div class="fixed top-0 left-0 w-full z-50 flex items-center justify-between py-4 px-6 h-16 bg-[#f7f9f3]">
<div class="flex items-center gap-4">
<label
for="mobile-menu-toggle"
class="lg:hidden cursor-pointer flex items-center justify-center w-10 h-10 bg-[#00698c] text-white rounded-lg hover:bg-[#004f6b] transition-colors"
aria-label="Toggle menu">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</label>
<%= image_tag "SITF-Horz-no-tag-logo.svg", class: "h-8 w-auto", alt: "Stocks in The Future" %>
</div>
<div class="hidden lg:block">
<%= render 'layouts/stock_ticker' %>
</div>
</div>
<div class="fixed w-full h-px z-40 top-16 bg-[#004f6b]"></div>
<%= render 'layouts/navbar', stocks: @navbar_stocks %>
<!-- Main: responsive margins and padding -->
<main class="min-h-screen overflow-auto px-4 sm:px-6 ml-0 lg:ml-50 mt-16 pb-6 bg-[#f7f9f3]">
<!-- Flash Messages -->
<% if notice.present? %>
<p class="mb-4 p-4 bg-green-50 border border-green-200 text-green-800 rounded-lg" id="notice"><%= notice %></p>
<% end %>
<% if alert.present? %>
<p class="mb-4 p-4 bg-red-50 border border-red-200 text-red-800 rounded-lg" id="alert"><%= alert %></p>
<% end %>
<%= yield %>
</main>
<% else %>
<main class="min-h-screen overflow-auto p-6 bg-[#f7f9f3]">
<%= yield %>
</main>
<% end %>
<!-- Trading Modal -->
<%= render 'shared/modal' %>
</body>
</html>

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
/* Email styles need to be inline */
</style>
</head>
<body>
<%= yield %>
</body>
</html>

View File

@@ -0,0 +1 @@
<%= yield %>