Skip to content

Commit 7fa3d01

Browse files
authored
Merge pull request #23 from MeMMa137/frontend
Frontend Update
2 parents 5716fca + 1dbd636 commit 7fa3d01

File tree

10 files changed

+499
-208
lines changed

10 files changed

+499
-208
lines changed

app/assets/stylesheets/application.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ h1, h2, h3, h4, h5, h6 {
467467
position: absolute;
468468
bottom: 0;
469469
left: 0;
470-
width: clamp(150px, 20vw, 280px);
470+
width: clamp(800px, 20vw, 280px);
471471
z-index: 2;
472472
}
473473

app/views/layouts/application.html.erb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
<title><%= content_for?(:title) ? yield(:title) : "Reboot" %></title>
77
<%= csrf_meta_tags %>
88
<meta name="csrf-token" content="<%= form_authenticity_token %>">
9+
<link rel="icon" type="image/png" href="https://files.slack.com/files-pri/T09V59WQY1E-F0A6UD211JS/animal.png?pub_secret=3e17f8e9df">
10+
<link rel="shortcut icon" type="image/png" href="https://files.slack.com/files-pri/T09V59WQY1E-F0A6UD211JS/animal.png?pub_secret=3e17f8e9df">
911
<link rel="stylesheet" href="/stylesheets/application.css?v=6">
1012
<script defer src="/javascripts/application.js?v=2"></script>
1113
</head>

app/views/pages/shop.html.erb

Lines changed: 128 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -4,210 +4,146 @@
44
<%= render "shared/navbar" %>
55

66
<main class="container">
7-
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem;">
7+
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
88
<h1 class="page-title" style="margin: 0;">Shop</h1>
99
<a href="/purchases" class="btn btn--secondary">Recent Purchases</a>
1010
</div>
1111

12-
<div style="display: grid; grid-template-columns: 250px 1fr; gap: 2rem;">
13-
<aside class="shop-sidebar card">
14-
<h3 style="margin: 0 0 1rem 0; color: #1f2430; font-size: 1.1rem;">Categories</h3>
15-
16-
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
17-
<button class="shop-category-btn shop-category-btn--active" data-category="all">
18-
All Items
19-
</button>
20-
<button class="shop-category-btn" data-category="economic">
21-
Economic
22-
</button>
23-
<button class="shop-category-btn" data-category="standard">
24-
Standard
25-
</button>
26-
<button class="shop-category-btn" data-category="quality">
27-
Quality
28-
</button>
29-
<button class="shop-category-btn" data-category="advanced">
30-
Advanced
31-
</button>
32-
<button class="shop-category-btn" data-category="professional">
33-
Professional
34-
</button>
35-
</div>
12+
<div class="shop-layout">
13+
<aside class="shop-categories card">
14+
<h3 class="shop-heading">Category</h3>
15+
<ul class="shop-category-list">
16+
<% categories = [ "Keyboard", "Mouse", "Monitor", "Headphones", "Webcam" ] %>
17+
<% categories.each_with_index do |cat, idx| %>
18+
<li>
19+
<button class="shop-category-item <%= 'is-active' if idx == 0 %>" data-target="cat-<%= cat.downcase %>">
20+
<%= cat %>
21+
</button>
22+
</li>
23+
<% end %>
24+
</ul>
3625
</aside>
3726

38-
<section>
39-
<h2 style="margin: 0 0 1.5rem 0; color: #1f2430;">Items</h2>
27+
<section class="shop-items card">
28+
<div class="shop-items__header">
29+
<h2 class="shop-heading" style="margin: 0;">Items</h2>
30+
<div aria-hidden="true" class="shop-cart">
31+
<img src="https://files.slack.com/files-pri/T09V59WQY1E-F0A793FGJ2V/bolt.png?pub_secret=7acc4044c5" alt="bolts" class="bolt-icon">
32+
</div>
33+
</div>
34+
35+
<% categories.each_with_index do |cat, idx| %>
36+
<% item = @shop_items.find { |i| i.name.to_s.downcase.strip == cat.downcase } %>
37+
<% base_cost = (item&.cost || 0).to_i %>
38+
<div id="cat-<%= cat.downcase %>" class="shop-item-detail <%= 'is-active' if idx == 0 %>">
39+
<div class="shop-item-detail__variants">
40+
<% variants = [
41+
['Standard grant', 'standard'],
42+
['Quality grant', 'quality'],
43+
['Advanced grant', 'advanced'],
44+
['Professional grant', 'professional']
45+
] %>
46+
<% images_for_keyboard = [
47+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A6SJ1AQAH/vecteezy_keyboard-3d-rendering-icon-illustration_28606613.png?pub_secret=9418a400cb',
48+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A6SHUUGN9/vecteezy_gaming-keyboard-with-anti-ghosting-technology-transparent_57571865.png?pub_secret=2fe417ad9b',
49+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A7QABPARW/vecteezy_rgb-illuminated-white-gaming-keyboard-top-view_52855142.png?pub_secret=3d3c0544c6',
50+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A6EHQKAUF/vecteezy_white-rgb-mechanical-gaming-keyboard-with-cable_52855199.png?pub_secret=3e689005bb'
51+
] if cat == 'Keyboard' %>
52+
<% images_for_mouse = [
53+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A7QDJR56C/vecteezy_computer-mouse-isolated-on-a-transparent-background_47833235.png?pub_secret=206f7975e4',
54+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A6PNNB8HH/vecteezy_ai-generated-computer-mouse-png-isolated-on-transparent_36113136.png?pub_secret=5328baa9cd',
55+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A6ZMVP5RA/vecteezy_ai-generated-computer-mouse-png-isolated-on-transparent_36112700.png?pub_secret=4a6941278c',
56+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A6ELUDWQP/vecteezy_ai-generated-computer-mouse-png-isolated-on-transparent_36112693.png?pub_secret=8a1b07b884'
57+
] if cat == 'Mouse' %>
58+
<% images_for_monitor = [
59+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A793DR88Z/10740609.png?pub_secret=edffb80446',
60+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A6ZNZN99A/3d-monitor-curved-free-png.webp?pub_secret=9d8649f57c',
61+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A6W5FN41Y/vecteezy_3d-monitor-for-office_53739745.png?pub_secret=6a16537f48',
62+
'https://files.slack.com/files-pri/T09V59WQY1E-F0A6EN1NVP1/vecteezy_sleek-black-computer-monitor-with-vibrant-red-abstract_56609224.png?pub_secret=5e30e2cd74'
63+
] if cat == 'Monitor' %>
64+
<% variants.each_with_index do |(label_text, key), variant_idx| %>
65+
<% img_src = (
66+
(cat == 'Keyboard' && images_for_keyboard && images_for_keyboard[variant_idx]) ||
67+
(cat == 'Mouse' && images_for_mouse && images_for_mouse[variant_idx]) ||
68+
(cat == 'Monitor' && images_for_monitor && images_for_monitor[variant_idx]) ||
69+
'/images/signin/hackclub.svg'
70+
) %>
71+
<% amount_map = { 'standard' => 50, 'quality' => 110, 'advanced' => 170, 'professional' => 230 } %>
72+
<% grant_amount = amount_map[key] || 0 %>
73+
<% bolts_map = { 'standard' => 500, 'quality' => 1100, 'advanced' => 1700, 'professional' => 2300 } %>
74+
<% base_bolts = bolts_map[key] || 0 %>
75+
<% price = base_bolts %>
76+
<% desc_text = "This item provide a #{grant_amount}$ HCB card grant to spend on a #{cat}" %>
77+
<div class="shop-variant">
78+
<div class="shop-variant__thumb">
79+
<img src="<%= img_src %>" alt="<%= label_text %>">
80+
</div>
4081

41-
<% if @shop_items.any? %>
42-
<div class="shop-grid">
43-
<% @shop_items.each do |item| %>
44-
<div class="shop-card card" data-id="<%= item.id %>" data-cost="<%= item.cost %>" data-category="<%= item.status || 'standard' %>">
45-
<% if item.image_url.present? %>
46-
<img class="shop-card__image" src="<%= item.image_url %>" alt="<%= item.name %>">
47-
<% else %>
48-
<div class="shop-card__image shop-card__image--placeholder">🪛</div>
49-
<% end %>
50-
51-
<div class="shop-card__body">
52-
<h3 class="shop-card__title"><%= item.name.presence || "Unnamed Item" %></h3>
53-
<p class="shop-card__description muted"><%= item.description.presence || "No description" %></p>
54-
55-
<% item_cost = item.cost || 0 %>
56-
<div class="shop-card__footer">
57-
<div>
58-
<span class="shop-card__price"><%= item_cost.to_i %> 🪛</span>
59-
<% if item.status.present? %>
60-
<span class="pill" style="background: #e8f0e8; color: #4a7c59; padding: 4px 8px; border-radius: 4px; font-size: 0.8rem; margin-left: 0.5rem;">
61-
<%= item.status.capitalize %>
62-
</span>
63-
<% end %>
64-
</div>
65-
<%= form_with url: purchase_path, method: :post, local: true, class: "purchase-form" do %>
66-
<input type="hidden" name="item_id" value="<%= item.id %>">
67-
<button type="submit" class="btn btn--primary"
68-
<%= 'disabled' if @current_user.balance < item_cost %>>
69-
<%= @current_user.balance >= item_cost ? 'Purchase' : 'Not enough screws' %>
70-
</button>
71-
<% end %>
82+
<div class="shop-variant__name"><%= label_text %></div>
83+
84+
<div class="shop-variant__meta">
85+
<button type="button"
86+
class="shop-variant__priceBox price-btn"
87+
data-item-id="<%= item&.id %>"
88+
data-name="<%= cat %>"
89+
data-variant="<%= key %>"
90+
data-display="<%= label_text %>"
91+
data-price="<%= price %>"
92+
data-grant="<%= grant_amount %>"
93+
data-bolts="<%= base_bolts %>"
94+
data-img="<%= img_src %>"
95+
data-desc="<%= desc_text.to_s.gsub('\"','&quot;') %>">
96+
<span class="shop-variant__price"><%= price %></span>
97+
<img src="https://files.slack.com/files-pri/T09V59WQY1E-F0A793FGJ2V/bolt.png?pub_secret=7acc4044c5" alt="bolts" class="bolt-icon">
98+
</button>
99+
<span class="shop-variant__pill shop-variant__pill--<%= key %>"><%= label_text %></span>
72100
</div>
101+
102+
<!-- Purchase action moved to modal -->
73103
</div>
74-
</div>
75-
<% end %>
76-
</div>
77-
<% else %>
78-
<div class="card" style="text-align: center; padding: 40px;">
79-
<p class="muted">No items in the shop yet. Check back soon!</p>
104+
<% end %>
105+
</div>
80106
</div>
81107
<% end %>
82108
</section>
83109
</div>
110+
<div class="card" style="margin-top: 12px; background: #fff3cd; border: 1px solid #ffeeba; color: #856404; padding: 10px; text-align: center;">
111+
Working progress! We're building the shop page, more items will be added soon!
112+
</div>
84113
</main>
85114

86-
<style>
87-
.shop-sidebar {
88-
height: fit-content;
89-
position: sticky;
90-
top: 20px;
91-
}
92-
93-
.shop-category-btn {
94-
background: #f5f5f3;
95-
border: none;
96-
color: #1f2430;
97-
padding: 12px 16px;
98-
border-radius: 8px;
99-
cursor: pointer;
100-
font-weight: 600;
101-
font-size: 0.95rem;
102-
transition: all 0.2s ease;
103-
text-align: left;
104-
}
105-
106-
.shop-category-btn:hover {
107-
background: #efefeb;
108-
}
109-
110-
.shop-category-btn--active {
111-
background: #d6a161;
112-
color: white;
113-
}
114-
115-
.shop-grid {
116-
display: grid;
117-
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
118-
gap: 1.5rem;
119-
}
120-
121-
.shop-card {
122-
padding: 0;
123-
overflow: hidden;
124-
}
125-
126-
.shop-card__image {
127-
width: 100%;
128-
height: 200px;
129-
object-fit: cover;
130-
}
131-
132-
.shop-card__image--placeholder {
133-
width: 100%;
134-
height: 200px;
135-
display: flex;
136-
align-items: center;
137-
justify-content: center;
138-
background: #f0f0f0;
139-
font-size: 4rem;
140-
}
141-
142-
.shop-card__body {
143-
padding: 1rem;
144-
}
145-
146-
.shop-card__title {
147-
margin: 0 0 0.5rem 0;
148-
font-size: 1rem;
149-
color: #1f2430;
150-
}
151-
152-
.shop-card__description {
153-
margin: 0 0 1rem 0;
154-
font-size: 0.9rem;
155-
line-height: 1.4;
156-
}
157-
158-
.shop-card__footer {
159-
display: flex;
160-
flex-direction: column;
161-
gap: 0.75rem;
162-
margin-top: 1rem;
163-
padding-top: 1rem;
164-
border-top: 1px solid #f0f0f0;
165-
}
166-
167-
.shop-card__price {
168-
font-weight: 700;
169-
color: #f25f2c;
170-
font-size: 1.1rem;
171-
}
172-
173-
.purchase-form {
174-
display: contents;
175-
}
176-
177-
@media (max-width: 768px) {
178-
main.container {
179-
display: block !important;
180-
}
181-
182-
.shop-sidebar {
183-
display: grid;
184-
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
185-
gap: 0.5rem;
186-
position: static;
187-
margin-bottom: 2rem;
188-
}
189-
}
190-
</style>
191-
192-
<script>
193-
const categoryBtns = document.querySelectorAll('.shop-category-btn');
194-
const shopCards = document.querySelectorAll('.shop-card');
195-
196-
categoryBtns.forEach(btn => {
197-
btn.addEventListener('click', () => {
198-
categoryBtns.forEach(b => b.classList.remove('shop-category-btn--active'));
199-
btn.classList.add('shop-category-btn--active');
200-
201-
const selectedCategory = btn.dataset.category;
202-
203-
shopCards.forEach(card => {
204-
const cardCategory = card.dataset.category;
205-
if (selectedCategory === 'all' || cardCategory === selectedCategory) {
206-
card.style.display = 'block';
207-
} else {
208-
card.style.display = 'none';
209-
}
210-
});
211-
});
212-
});
213-
</script>
115+
<!-- Item Modal -->
116+
<div id="shop-item-modal" class="modal modal--hidden" data-user-balance="<%= @current_user.balance.to_i %>">
117+
<div class="modal__backdrop"></div>
118+
<div class="modal__content card">
119+
<div class="modal__header">
120+
<h3 id="shop-modal-title" class="modal__title">Item</h3>
121+
<button type="button" class="modal__close" aria-label="Close">&times;</button>
122+
</div>
123+
<div class="shop-modal__body">
124+
<img id="shop-modal-image" class="shop-modal__image" src="/images/signin/hackclub.svg" alt="item">
125+
<p id="shop-modal-desc" class="shop-modal__desc muted">Description</p>
126+
<div class="shop-modal__qty" style="display:flex;align-items:center;gap:8px;">
127+
<label for="shop-modal-qty" class="muted">Quantity</label>
128+
<input id="shop-modal-qty" type="number" min="1" step="1" value="1" style="width:80px;">
129+
</div>
130+
<div class="shop-modal__price">
131+
<span id="shop-modal-price">0</span>
132+
<img src="https://files.slack.com/files-pri/T09V59WQY1E-F0A793FGJ2V/bolt.png?pub_secret=7acc4044c5" alt="bolts" class="bolt-icon">
133+
</div>
134+
<div id="shop-modal-warning" style="display:none;background:#fdecea;border:1px solid #f5c2c7;color:#842029;padding:8px 12px;border-radius:8px;">
135+
Not enough bolts to purchase. You need <strong><span id="shop-modal-shortage">0</span></strong> more.
136+
</div>
137+
<%= form_with url: purchase_path, method: :post, local: true, id: "shop-modal-form" do %>
138+
<input type="hidden" name="item_id" id="shop-modal-item-id" value="">
139+
<input type="hidden" name="variant" id="shop-modal-variant" value="">
140+
<button id="shop-modal-buy" type="submit" class="btn btn--primary btn--block">Purchase</button>
141+
<% end %>
142+
</div>
143+
</div>
144+
<style>
145+
.shop-modal__body { display: grid; gap: 12px; }
146+
.shop-modal__image { width: 100%; height: 180px; border-radius: 10px; object-fit: cover; background: var(--paper-alt); }
147+
.shop-modal__price { display: inline-flex; align-items: center; gap: 8px; background: #efd1a4; padding: 8px 12px; border-radius: 12px; width: fit-content; }
148+
</style>
149+
</div>

app/views/pages/signin.html.erb

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@
22
<% content_for :page, "signin" %>
33

44
<div class="signin-page">
5-
<img src="/images/signin/hackclub.svg" class="signin-flag" alt="Hack Club 2025">
5+
<a href="https://hackclub.com/" target="_blank" rel="noopener">
6+
<img src="/images/signin/hackclub.svg" class="signin-flag" alt="Hack Club 2025">
7+
</a>
68

79
<div class="signin-content">
810
<img src="https://files.slack.com/files-pri/T09V59WQY1E-F0A6LSXCXPF/image.png?pub_secret=dc0d11081a" class="signin-crane-text" alt="Reboot">
911

10-
<p class="signin-subtitle">Restore old projects --> upgrade your desktop setup!</p>
11-
1212
<%= form_tag("/auth/hack_club", method: :post) do %>
13-
<button type="submit" class="signin-btn">Start Now</button>
13+
<button type="submit" class="signin-btn" style="background: transparent; padding: 0; box-shadow: none; border: none;">
14+
<img
15+
src="https://files.slack.com/files-pri/T09V59WQY1E-F0A7999BL3T/startbutton.png?pub_secret=346938b95a"
16+
alt="Start Now"
17+
class="signin-start-img"
18+
onerror="this.onerror=null;this.src='/img/signin/startButton.PNG';"
19+
>
20+
</button>
1421
<% end %>
22+
23+
<p class="signin-subtitle">Restore old projects --> upgrade your desktop setup!</p>
1524
</div>
1625

1726
<img src="/images/signin/animal.png" class="signin-mole" alt="Mole">

app/views/shared/_navbar.html.erb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
<% end %>
1414
</span>
1515
<button id="signout-btn" class="btn btn--ghost">Sign out</button>
16-
<div class="coins" title="Your screws"><%= @current_user&.balance&.to_i || 0 %> 🪛</div>
16+
<div class="coins" title="Your screws" style="display:inline-flex;align-items:center;gap:6px;">
17+
<%= @current_user&.balance&.to_i || 0 %>
18+
<img src="https://files.slack.com/files-pri/T09V59WQY1E-F0A793FGJ2V/bolt.png?pub_secret=7acc4044c5" alt="bolts" style="width:18px;height:18px;">
19+
</div>
1720
</div>
1821

1922
<style>

0 commit comments

Comments
 (0)