Skip to content

Commit a2a01eb

Browse files
authored
Merge pull request #817 from ShreyasLakhani/feature/add-merch-store
Feature/add merch store
2 parents 453dacd + a440db4 commit a2a01eb

21 files changed

+2347
-0
lines changed

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
# No special permissions needed for public repositories
55
GITHUB_TOKEN=your_github_token_here
66

7+
# Shopify Configuration (for Merch Store)
8+
# Get these from: Shopify Admin > Settings > Apps and sales channels > Develop apps
9+
# Required scopes: unauthenticated_read_product_listings, unauthenticated_write_checkouts
10+
SHOPIFY_STORE_DOMAIN=your-store.myshopify.com
11+
SHOPIFY_STOREFRONT_ACCESS_TOKEN=your_storefront_access_token_here
12+
713
# Firebase Configuration (if needed)
814
# FIREBASE_API_KEY=your_firebase_api_key
915
# FIREBASE_AUTH_DOMAIN=your_firebase_auth_domain

docusaurus.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ const config: Config = {
201201
label: "🎙️ Podcast",
202202
to: "/podcasts/",
203203
},
204+
{
205+
label: "🛍️ Merch Store",
206+
to: "/merch",
207+
},
204208
],
205209
},
206210
// Search disabled until Algolia is properly configured
@@ -265,6 +269,9 @@ const config: Config = {
265269
// ✅ Add this customFields object to expose the token to the client-side
266270
customFields: {
267271
gitToken: process.env.DOCUSAURUS_GIT_TOKEN,
272+
// Shopify credentials for merch store
273+
SHOPIFY_STORE_DOMAIN: process.env.SHOPIFY_STORE_DOMAIN || 'junh9v-gw.myshopify.com',
274+
SHOPIFY_STOREFRONT_ACCESS_TOKEN: process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN || '2503dfbf93132b42e627e7d53b3ba3e9',
268275
hooks: {
269276
onBrokenMarkdownLinks: "warn",
270277
},

src/components/merch/FilterBar.css

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/* Filter Bar Styles */
2+
3+
.filter-bar {
4+
background: var(--ifm-card-background-color);
5+
border-bottom: 1px solid var(--ifm-color-emphasis-200);
6+
position: sticky;
7+
top: 60px;
8+
z-index: 100;
9+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
10+
}
11+
12+
.filter-bar-container {
13+
max-width: 1400px;
14+
margin: 0 auto;
15+
padding: 1.5rem 2rem;
16+
display: flex;
17+
justify-content: space-between;
18+
align-items: center;
19+
gap: 2rem;
20+
flex-wrap: wrap;
21+
}
22+
23+
/* Filter Section */
24+
.filter-section {
25+
flex: 1;
26+
min-width: 300px;
27+
}
28+
29+
.filter-header {
30+
display: flex;
31+
align-items: center;
32+
gap: 0.5rem;
33+
margin-bottom: 1rem;
34+
color: var(--ifm-font-color-base);
35+
}
36+
37+
.filter-title {
38+
font-weight: 600;
39+
font-size: 0.875rem;
40+
text-transform: uppercase;
41+
letter-spacing: 0.5px;
42+
}
43+
44+
/* Category Filters */
45+
.category-filters {
46+
display: flex;
47+
gap: 0.75rem;
48+
flex-wrap: wrap;
49+
}
50+
51+
.category-button {
52+
display: flex;
53+
align-items: center;
54+
gap: 0.5rem;
55+
padding: 0.5rem 1rem;
56+
background: var(--ifm-color-emphasis-100);
57+
border: 2px solid transparent;
58+
border-radius: 8px;
59+
font-size: 0.875rem;
60+
font-weight: 500;
61+
color: #2d3748;
62+
cursor: pointer;
63+
transition: all 0.2s ease;
64+
}
65+
66+
.category-button:hover {
67+
background: var(--ifm-color-emphasis-200);
68+
transform: translateY(-2px);
69+
}
70+
71+
.category-button.active {
72+
background: var(--ifm-color-primary);
73+
border-color: var(--ifm-color-primary);
74+
color: #ffffff !important;
75+
font-weight: 600;
76+
}
77+
78+
.category-icon {
79+
font-size: 1.25rem;
80+
}
81+
82+
.category-label {
83+
white-space: nowrap;
84+
}
85+
86+
/* Sort Section */
87+
.sort-section {
88+
min-width: 200px;
89+
}
90+
91+
.sort-select {
92+
width: 100%;
93+
padding: 0.625rem 1rem;
94+
background: var(--ifm-color-emphasis-100);
95+
border: 2px solid var(--ifm-color-emphasis-200);
96+
border-radius: 8px;
97+
font-size: 0.875rem;
98+
font-weight: 500;
99+
color: var(--ifm-font-color-base);
100+
cursor: pointer;
101+
transition: all 0.2s ease;
102+
appearance: none;
103+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23666' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
104+
background-repeat: no-repeat;
105+
background-position: right 1rem center;
106+
padding-right: 2.5rem;
107+
}
108+
109+
.sort-select:hover {
110+
border-color: var(--ifm-color-primary);
111+
}
112+
113+
.sort-select:focus {
114+
outline: none;
115+
border-color: var(--ifm-color-primary);
116+
box-shadow: 0 0 0 3px var(--ifm-color-primary-lightest);
117+
}
118+
119+
/* Responsive Design */
120+
@media (max-width: 768px) {
121+
.filter-bar-container {
122+
padding: 1rem;
123+
flex-direction: column;
124+
align-items: stretch;
125+
}
126+
127+
.filter-section {
128+
min-width: 100%;
129+
}
130+
131+
.category-filters {
132+
gap: 0.5rem;
133+
}
134+
135+
.category-button {
136+
padding: 0.5rem 0.75rem;
137+
font-size: 0.8125rem;
138+
}
139+
140+
.category-icon {
141+
font-size: 1rem;
142+
}
143+
144+
.sort-section {
145+
min-width: 100%;
146+
}
147+
148+
.filter-bar {
149+
top: 0;
150+
}
151+
}
152+
153+
/* Dark Mode */
154+
[data-theme="dark"] .filter-bar {
155+
background: var(--ifm-background-surface-color);
156+
border-bottom-color: var(--ifm-color-emphasis-300);
157+
}
158+
159+
[data-theme="dark"] .category-button {
160+
background: var(--ifm-color-emphasis-200);
161+
color: var(--ifm-font-color-base);
162+
}
163+
164+
[data-theme="dark"] .category-button.active {
165+
background: rgba(16, 185, 129, 0.15);
166+
border-color: var(--ifm-color-primary);
167+
color: #10b981 !important;
168+
}
169+
170+
[data-theme="dark"] .category-button:hover {
171+
background: var(--ifm-color-emphasis-300);
172+
}
173+
174+
[data-theme="dark"] .sort-select {
175+
background: var(--ifm-color-emphasis-200);
176+
border-color: var(--ifm-color-emphasis-300);
177+
}

src/components/merch/FilterBar.tsx

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import React from "react";
2+
import { Filter, SlidersHorizontal } from "lucide-react";
3+
import "./FilterBar.css";
4+
5+
interface FilterBarProps {
6+
selectedCategory: string;
7+
onCategoryChange: (category: string) => void;
8+
sortBy: string;
9+
onSortChange: (sortBy: string) => void;
10+
}
11+
12+
const categories = [
13+
{ id: "all", label: "All Products", icon: "🛍️" },
14+
{ id: "t-shirts", label: "T-Shirts", icon: "👕" },
15+
{ id: "hoodies", label: "Hoodies", icon: "🧥" },
16+
{ id: "accessories", label: "Accessories", icon: "🎒" },
17+
];
18+
19+
const sortOptions = [
20+
{ value: "featured", label: "Featured" },
21+
{ value: "price-low", label: "Price: Low to High" },
22+
{ value: "price-high", label: "Price: High to Low" },
23+
{ value: "name", label: "Name: A to Z" },
24+
];
25+
26+
const FilterBar: React.FC<FilterBarProps> = ({
27+
selectedCategory,
28+
onCategoryChange,
29+
sortBy,
30+
onSortChange,
31+
}) => {
32+
return (
33+
<div className="filter-bar">
34+
<div className="filter-bar-container">
35+
{/* Category Filters */}
36+
<div className="filter-section">
37+
<div className="filter-header">
38+
<Filter size={18} />
39+
<span className="filter-title">Categories</span>
40+
</div>
41+
<div className="category-filters">
42+
{categories.map((cat) => (
43+
<button
44+
key={cat.id}
45+
className={`category-button ${
46+
selectedCategory === cat.id ? "active" : ""
47+
}`}
48+
onClick={() => onCategoryChange(cat.id)}
49+
>
50+
<span className="category-icon">{cat.icon}</span>
51+
<span className="category-label">{cat.label}</span>
52+
</button>
53+
))}
54+
</div>
55+
</div>
56+
57+
{/* Sort Options */}
58+
<div className="sort-section">
59+
<div className="filter-header">
60+
<SlidersHorizontal size={18} />
61+
<span className="filter-title">Sort By</span>
62+
</div>
63+
<select
64+
className="sort-select"
65+
value={sortBy}
66+
onChange={(e) => onSortChange(e.target.value)}
67+
>
68+
{sortOptions.map((option) => (
69+
<option key={option.value} value={option.value}>
70+
{option.label}
71+
</option>
72+
))}
73+
</select>
74+
</div>
75+
</div>
76+
</div>
77+
);
78+
};
79+
80+
export default FilterBar;

0 commit comments

Comments
 (0)