This is a submission for the KendoReact Free Components Challenge.
What I Built
Here is the list of all KendoReact free components used in the previous App.jsx
:
1️⃣ AppBar - Used for the top navigation bar displaying the store title and user actions.
2️⃣ Avatar - Displays the user’s profile image in the AppBar.
3️⃣ PanelBar - Provides collapsible panels for categories, sizes, and colors in the filter section.
4️⃣ PanelBarItem - Individual items within the PanelBar for organizing filter options.
5️⃣ Card - Used for displaying cart contents, collections, and other boxed content.
6️⃣ GridLayout - Organizes products in a grid layout within ExpansionPanels.
7️⃣ GridLayoutItem - Defines individual items within the GridLayout for product cards.
8️⃣ StackLayout - Aligns elements horizontally or vertically (e.g., in filters, footer).
9️⃣ TabStrip - Creates tabs for Shop, Wishlist, and Profile sections.
🔟 TabStripTab - Individual tabs within the TabStrip component.
1️⃣1️⃣ Drawer - Side navigation menu for additional options like Home and Contact.
1️⃣2️⃣ DrawerItem - Items within the Drawer for navigation links.
1️⃣3️⃣ ExpansionPanel - Collapsible sections for displaying multiple product collections.
1️⃣4️⃣ Breadcrumb - Shows navigation path (e.g., Home > Shop > Category).
1️⃣5️⃣ BottomNavigation - Footer navigation bar with Home, Cart, and Profile links.
1️⃣6️⃣ BottomNavigationItem - Individual items in the BottomNavigation.
1️⃣7️⃣ TileLayout - Used for the promotional banner section.
1️⃣8️⃣ TileLayoutItem - Individual tiles within the TileLayout.
1️⃣9️⃣ Menu - Dropdown menu for additional navigation options (e.g., Shop More).
2️⃣0️⃣ MenuItem - Items within the Menu component.
2️⃣1️⃣ Button - General-purpose buttons for actions like adding to cart, submitting forms, etc.
2️⃣2️⃣ ButtonGroup - Groups buttons together (e.g., in Grid actions).
2️⃣3️⃣ DropDownList - Dropdown selection for sorting, sizes, and colors.
2️⃣4️⃣ AutoComplete - Search input with autocomplete suggestions from product names.
2️⃣5️⃣ NumericTextBox - Numeric input for quantity selection and review ratings.
2️⃣6️⃣ Input - Text input for search, login, shipping, and payment fields.
2️⃣7️⃣ Switch - Toggle for showing/hiding advanced filters.
2️⃣8️⃣ Checkbox - Checkbox for advanced filter options (e.g., "In Stock Only").
2️⃣9️⃣ RadioButton - Individual radio buttons within RadioButtonGroup.
3️⃣0️⃣ RadioButtonGroup - Group of radio buttons for filter options (e.g., New/Sale).
3️⃣1️⃣ Slider - Slider for selecting a price range in advanced filters.
3️⃣2️⃣ TextArea - Text area for writing reviews or contact messages.
3️⃣3️⃣ Calendar - Calendar picker for selecting delivery dates (not used in final UI but imported).
3️⃣4️⃣ DatePicker - Date picker for selecting delivery dates (not used in final UI but imported).
3️⃣5️⃣ DateInput - Manual date input field (not used in final UI but imported).
3️⃣6️⃣ DateTimePicker - Date and time picker for delivery scheduling.
3️⃣7️⃣ Notification - Success notifications for adding to cart or placing an order.
3️⃣8️⃣ Grid - Tabular display for products, cart, wishlist, and order history.
3️⃣9️⃣ GridColumn - Defines columns within the Grid component.
4️⃣0️⃣ Tooltip - Hover tooltip for filter information button.
4️⃣1️⃣ Popover - Popover component (imported but not used in final UI).
4️⃣2️⃣ ListBox - List selection for categories, sizes, and colors in the PanelBar.
4️⃣3️⃣ Badge - Badge for displaying cart count (not used in final UI but imported).
4️⃣4️⃣ Loader - Loading indicator during checkout processing.
4️⃣5️⃣ Skeleton - Placeholder UI component (not used in final UI but imported).
4️⃣6️⃣ ProgressBar - Progress bar showing cart fill level.
4️⃣7️⃣ Dialog - Modal dialogs for login, product details, checkout, order history, wishlist, and contact form.
4️⃣8️⃣ SvgIcon - SVG icons for Home, User, Cart, Calendar, Email, Star, Search, Menu, Close, LinkedIn, GitHub, Twitter, and Globe.
Total Components Used: 48
App.jsx
import React, { useState } from 'react';
import './App.css';
// KendoReact Free Components Imports (Expanded to Use More)
import {
AppBar,
Avatar,
PanelBar,
PanelBarItem,
Card,
GridLayout,
GridLayoutItem,
StackLayout,
TabStrip,
TabStripTab,
Drawer,
DrawerItem,
ExpansionPanel,
Breadcrumb,
BottomNavigation,
BottomNavigationItem,
TileLayout,
TileLayoutItem,
Menu,
MenuItem,
} from '@progress/kendo-react-layout';
import { Button, ButtonGroup } from '@progress/kendo-react-buttons';
import { DropDownList, AutoComplete } from '@progress/kendo-react-dropdowns';
import { NumericTextBox, Input, Switch, Checkbox, RadioButton, RadioButtonGroup, Slider, TextArea } from '@progress/kendo-react-inputs';
import { Calendar, DatePicker, DateInput, DateTimePicker } from '@progress/kendo-react-dateinputs';
import { Notification } from '@progress/kendo-react-notification';
import { Grid, GridColumn } from '@progress/kendo-react-grid';
import { Tooltip, Popover } from '@progress/kendo-react-tooltip';
import { ListBox } from '@progress/kendo-react-listbox';
import { Badge, Loader, Skeleton } from '@progress/kendo-react-indicators';
import { ProgressBar } from '@progress/kendo-react-progressbars';
import { Dialog } from '@progress/kendo-react-dialogs';
import { SvgIcon } from '@progress/kendo-react-common';
import {
homeIcon,
userIcon,
cartIcon,
calendarIcon,
emailIcon,
starIcon,
searchIcon,
menuIcon,
closeIcon,
linkedinIcon,
githubIcon,
twitterIcon,
globeIcon,
} from '@progress/kendo-svg-icons';
function App() {
// Sample T-Shirt Products (Expanded Massively)
const sampleProducts = Array.from({ length: 100 }, (_, i) => ({
id: i + 1,
name: `T-Shirt ${i + 1}`,
price: (15 + i * 0.5).toFixed(2),
category: ['Men', 'Women', 'Kids'][i % 3],
stock: Math.floor(Math.random() * 100),
description: `A premium T-shirt for ${['casual wear', 'sports', 'style'][i % 3]}.`,
rating: (3.5 + Math.random() * 1.5).toFixed(1),
image: `https://via.placeholder.com/150?text=T-Shirt+${i + 1}`,
sizes: ['XS', 'S', 'M', 'L', 'XL', 'XXL'],
colors: ['Red', 'Blue', 'Green', 'Black', 'White'],
}));
// Categories and Other Data
const categories = ['All', 'Men', 'Women', 'Kids'];
const sortOptions = ['Price Low to High', 'Price High to Low', 'Rating High to Low'];
const sizes = ['XS', 'S', 'M', 'L', 'XL', 'XXL'];
const colors = ['Red', 'Blue', 'Green', 'Black', 'White'];
// State Management (Expanded)
const [products] = useState(sampleProducts);
const [selectedCategory, setSelectedCategory] = useState('All');
const [cart, setCart] = useState([]);
const [showNotification, setShowNotification] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const [sortOption, setSortOption] = useState('Price Low to High');
const [quantity, setQuantity] = useState(1);
const [deliveryDate, setDeliveryDate] = useState(null);
const [showFilters, setShowFilters] = useState(false);
const [user, setUser] = useState({ name: 'Guest', email: '', avatar: 'https://via.placeholder.com/50' });
const [showLogin, setShowLogin] = useState(false);
const [loginEmail, setLoginEmail] = useState('');
const [loginPassword, setLoginPassword] = useState('');
const [showCheckout, setShowCheckout] = useState(false);
const [checkoutStep, setCheckoutStep] = useState(0);
const [shippingInfo, setShippingInfo] = useState({ address: '', city: '', zip: '', country: '' });
const [paymentInfo, setPaymentInfo] = useState({ cardNumber: '', expiry: '', cvv: '', cardHolder: '' });
const [orderHistory, setOrderHistory] = useState([]);
const [showOrderHistory, setShowOrderHistory] = useState(false);
const [selectedProduct, setSelectedProduct] = useState(null);
const [showProductDetails, setShowProductDetails] = useState(false);
const [reviews, setReviews] = useState({});
const [drawerExpanded, setDrawerExpanded] = useState(false);
const [tabSelected, setTabSelected] = useState(0);
const [showWishlist, setShowWishlist] = useState(false);
const [wishlist, setWishlist] = useState([]);
const [showContactForm, setShowContactForm] = useState(false);
const [contactForm, setContactForm] = useState({ name: '', email: '', message: '' });
const [promoCode, setPromoCode] = useState('');
const [discount, setDiscount] = useState(0);
const [loading, setLoading] = useState(false);
// Handlers
const handleAddToCart = (item) => {
setCart((prev) => [...prev, { ...item, quantity }]);
setShowNotification(true);
setTimeout(() => setShowNotification(false), 3000);
};
const handleRemoveFromCart = (index) => {
setCart((prev) => prev.filter((_, i) => i !== index));
};
const handleAddToWishlist = (item) => {
setWishlist((prev) => [...prev, item]);
};
const handleRemoveFromWishlist = (index) => {
setWishlist((prev) => prev.filter((_, i) => i !== index));
};
const handleLogin = () => {
if (loginEmail && loginPassword) {
setUser({ name: loginEmail.split('@')[0], email: loginEmail, avatar: 'https://via.placeholder.com/50' });
setShowLogin(false);
}
};
const handleCheckout = () => {
if (checkoutStep === 0 && shippingInfo.address && shippingInfo.city && shippingInfo.zip) {
setCheckoutStep(1);
} else if (checkoutStep === 1 && paymentInfo.cardNumber && paymentInfo.expiry && paymentInfo.cvv) {
setCheckoutStep(2);
} else if (checkoutStep === 2) {
setLoading(true);
setTimeout(() => {
const total = cart.reduce((sum, item) => sum + item.price * item.quantity, 0);
const finalTotal = total - (total * discount) / 100;
const order = {
id: Date.now(),
items: [...cart],
total: finalTotal.toFixed(2),
date: new Date().toLocaleDateString(),
status: 'Pending',
shipping: { ...shippingInfo },
payment: { ...paymentInfo },
};
setOrderHistory((prev) => [...prev, order]);
setCart([]);
setShowCheckout(false);
setCheckoutStep(0);
setShowNotification(true);
setLoading(false);
setTimeout(() => setShowNotification(false), 3000);
}, 2000);
}
};
const handleViewProduct = (item) => {
setSelectedProduct(item);
setShowProductDetails(true);
};
const handleAddReview = (productId, comment, rating) => {
setReviews((prev) => ({
...prev,
[productId]: [...(prev[productId] || []), { user: user.name, comment, rating }],
}));
};
const handleApplyPromo = () => {
if (promoCode === 'SAVE20') setDiscount(20);
else if (promoCode === 'SAVE10') setDiscount(10);
else setDiscount(0);
};
// Filtering and Sorting
const filteredProducts = searchQuery
? products.filter((p) => p.name.toLowerCase().includes(searchQuery.toLowerCase()))
: selectedCategory === 'All'
? products
: products.filter((p) => p.category === selectedCategory);
const sortedProducts = [...filteredProducts].sort((a, b) => {
if (sortOption === 'Price Low to High') return a.price - b.price;
if (sortOption === 'Price High to Low') return b.price - a.price;
return b.rating - a.rating;
});
return (
<div className="App">
{/* AppBar */}
<AppBar className="appbar">
<Button icon="menu" onClick={() => setDrawerExpanded(!drawerExpanded)} />
<Avatar type="image" shape="circle" size="medium" imageUrl={user.avatar} onClick={() => setShowLogin(true)} />
<h1>T-Shirt Mega Store</h1>
<StackLayout gap={10} orientation="horizontal" className="appbar-actions">
<Button onClick={() => setShowWishlist(true)}>
<SvgIcon icon={starIcon} /> Wishlist ({wishlist.length})
</Button>
<Button onClick={() => setShowOrderHistory(true)}>
<SvgIcon icon={calendarIcon} /> Orders
</Button>
<Button icon="cart">{cart.length}</Button>
</StackLayout>
</AppBar>
{/* Drawer Navigation */}
<Drawer
expanded={drawerExpanded}
position="start"
mode="push"
onOverlayClick={() => setDrawerExpanded(false)}
>
<DrawerItem>
<SvgIcon icon={homeIcon} /> Home
</DrawerItem>
<DrawerItem onClick={() => setShowContactForm(true)}>
<SvgIcon icon={emailIcon} /> Contact Us
</DrawerItem>
<DrawerItem onClick={() => setShowWishlist(true)}>
<SvgIcon icon={starIcon} /> Wishlist
</DrawerItem>
</Drawer>
<div className="content">
{/* Promotional Banner */}
<TileLayout columns={1} gap={10}>
<TileLayoutItem>
<div className="promo-banner">
<h2>Summer Sale Extravaganza!</h2>
<p>Use code SAVE20 for 20% off!</p>
</div>
</TileLayoutItem>
</TileLayout>
{/* Breadcrumb */}
<Breadcrumb items={[{ text: 'Home' }, { text: 'Shop' }, { text: selectedCategory }]} />
{/* Main Content Tabs */}
<TabStrip selected={tabSelected} onSelect={(e) => setTabSelected(e.selected)}>
<TabStripTab title="Shop">
{/* Filters */}
<GridLayout cols={[{ width: '25%' }, { width: '75%' }]} gap={{ rows: 10, cols: 10 }}>
<GridLayoutItem>
<PanelBar>
<PanelBarItem title="Categories">
<ListBox
data={categories}
value={selectedCategory}
onChange={(e) => setSelectedCategory(e.value)}
/>
</PanelBarItem>
<PanelBarItem title="Sizes">
<ListBox data={sizes} />
</PanelBarItem>
<PanelBarItem title="Colors">
<ListBox data={colors} />
</PanelBarItem>
</PanelBar>
</GridLayoutItem>
<GridLayoutItem>
<StackLayout gap={15} orientation="horizontal" className="filters">
<AutoComplete data={products.map((p) => p.name)} value={searchQuery} onChange={(e) => setSearchQuery(e.value)} placeholder="Search..." />
<DropDownList data={sortOptions} value={sortOption} onChange={(e) => setSortOption(e.value)} />
<NumericTextBox min={1} value={quantity} onChange={(e) => setQuantity(e.value || 1)} />
<DateTimePicker value={deliveryDate} onChange={(e) => setDeliveryDate(e.value)} />
<Switch checked={showFilters} onChange={(e) => setShowFilters(e.checked)} label="Advanced Filters" />
<Tooltip anchorElement="target" position="top">
<Button title="Filter Info"><SvgIcon icon={searchIcon} /></Button>
</Tooltip>
</StackLayout>
{/* Advanced Filters */}
{showFilters && (
<ExpansionPanel title="Advanced Filters">
<StackLayout gap={10}>
<Checkbox label="In Stock Only" />
<RadioButtonGroup
data={[{ label: 'New', value: 'new' }, { label: 'Sale', value: 'sale' }]}
defaultValue="new"
/>
<Slider min={0} max={50} step={5} defaultValue={20} />
</StackLayout>
</ExpansionPanel>
)}
{/* Product Grid */}
<Grid data={sortedProducts.slice(0, 50)} className="product-grid">
<GridColumn field="name" title="Name" />
<GridColumn field="price" title="Price" cell={(props) => <td>${props.dataItem.price}</td>} />
<GridColumn field="category" title="Category" />
<GridColumn field="stock" title="Stock" />
<GridColumn field="rating" title="Rating" cell={(props) => <td>{props.dataItem.rating} <SvgIcon icon={starIcon} /></td>} />
<GridColumn
title="Actions"
cell={(props) => (
<td>
<ButtonGroup>
<Button onClick={() => handleAddToCart(props.dataItem)}><SvgIcon icon={cartIcon} /></Button>
<Button onClick={() => handleViewProduct(props.dataItem)}>View</Button>
<Button onClick={() => handleAddToWishlist(props.dataItem)}><SvgIcon icon={starIcon} /></Button>
</ButtonGroup>
</td>
)}
/>
</Grid>
</GridLayoutItem>
</GridLayout>
{/* Cart */}
<Card className="cart">
<h3>Your Cart</h3>
{cart.length === 0 ? (
<p>Empty</p>
) : (
<>
<Grid data={cart}>
<GridColumn field="name" title="Item" />
<GridColumn field="price" title="Price" cell={(props) => <td>${props.dataItem.price}</td>} />
<GridColumn field="quantity" title="Qty" />
<GridColumn
title="Remove"
cell={(props) => <td><Button onClick={() => handleRemoveFromCart(props.dataIndex)}>Remove</Button></td>}
/>
</Grid>
<p>Total: ${cart.reduce((sum, item) => sum + item.price * item.quantity, 0).toFixed(2)}</p>
<Input placeholder="Promo Code" value={promoCode} onChange={(e) => setPromoCode(e.value)} />
<Button onClick={handleApplyPromo}>Apply Promo</Button>
<p>Discount: {discount}%</p>
<Button onClick={() => setShowCheckout(true)}>Checkout</Button>
</>
)}
</Card>
</TabStripTab>
<TabStripTab title="Wishlist">
<Grid data={wishlist}>
<GridColumn field="name" title="Name" />
<GridColumn field="price" title="Price" cell={(props) => <td>${props.dataItem.price}</td>} />
<GridColumn
title="Actions"
cell={(props) => (
<td>
<Button onClick={() => handleAddToCart(props.dataItem)}>Add to Cart</Button>
<Button onClick={() => handleRemoveFromWishlist(props.dataIndex)}>Remove</Button>
</td>
)}
/>
</Grid>
</TabStripTab>
<TabStripTab title="Profile">
<Card>
<h3>User Profile</h3>
<p>Name: {user.name}</p>
<p>Email: {user.email || 'Not logged in'}</p>
<Button onClick={() => setShowLogin(true)}>Login/Update</Button>
</Card>
</TabStripTab>
</TabStrip>
{/* Modals */}
{showLogin && (
<Dialog title="Login" onClose={() => setShowLogin(false)}>
<StackLayout gap={10}>
<Input placeholder="Email" value={loginEmail} onChange={(e) => setLoginEmail(e.value)} />
<Input type="password" placeholder="Password" value={loginPassword} onChange={(e) => setLoginPassword(e.value)} />
<Button onClick={handleLogin}>Login</Button>
</StackLayout>
</Dialog>
)}
{showProductDetails && selectedProduct && (
<Dialog title={selectedProduct.name} onClose={() => setShowProductDetails(false)} width={500}>
<img src={selectedProduct.image} alt={selectedProduct.name} className="product-image" />
<p>{selectedProduct.description}</p>
<p>Price: ${selectedProduct.price}</p>
<p>Rating: {selectedProduct.rating} <SvgIcon icon={starIcon} /></p>
<DropDownList data={selectedProduct.sizes} defaultValue="M" />
<DropDownList data={selectedProduct.colors} defaultValue="Black" />
<Button onClick={() => handleAddToCart(selectedProduct)}>Add to Cart</Button>
<ExpansionPanel title="Reviews">
{(reviews[selectedProduct.id] || []).map((r, i) => (
<p key={i}>{r.user}: {r.comment} ({r.rating}/5)</p>
))}
<TextArea placeholder="Add a review" />
<NumericTextBox min={1} max={5} defaultValue={5} />
<Button onClick={() => handleAddReview(selectedProduct.id, 'Great!', 5)}>Submit Review</Button>
</ExpansionPanel>
</Dialog>
)}
{showCheckout && (
<Dialog title="Checkout" onClose={() => setShowCheckout(false)} width={600}>
{loading ? <Loader /> : (
<>
<div className="checkout-steps">
<span className={checkoutStep === 0 ? 'active' : ''}>Shipping</span>
<span className={checkoutStep === 1 ? 'active' : ''}>Payment</span>
<span className={checkoutStep === 2 ? 'active' : ''}>Confirm</span>
</div>
{checkoutStep === 0 && (
<StackLayout gap={10}>
<Input placeholder="Address" value={shippingInfo.address} onChange={(e) => setShippingInfo({ ...shippingInfo, address: e.value })} />
<Input placeholder="City" value={shippingInfo.city} onChange={(e) => setShippingInfo({ ...shippingInfo, city: e.value })} />
<Input placeholder="ZIP" value={shippingInfo.zip} onChange={(e) => setShippingInfo({ ...shippingInfo, zip: e.value })} />
<Input placeholder="Country" value={shippingInfo.country} onChange={(e) => setShippingInfo({ ...shippingInfo, country: e.value })} />
</StackLayout>
)}
{checkoutStep === 1 && (
<StackLayout gap={10}>
<Input placeholder="Card Number" value={paymentInfo.cardNumber} onChange={(e) => setPaymentInfo({ ...paymentInfo, cardNumber: e.value })} />
<Input placeholder="Expiry (MM/YY)" value={paymentInfo.expiry} onChange={(e) => setPaymentInfo({ ...paymentInfo, expiry: e.value })} />
<Input placeholder="CVV" value={paymentInfo.cvv} onChange={(e) => setPaymentInfo({ ...paymentInfo, cvv: e.value })} />
<Input placeholder="Card Holder" value={paymentInfo.cardHolder} onChange={(e) => setPaymentInfo({ ...paymentInfo, cardHolder: e.value })} />
</StackLayout>
)}
{checkoutStep === 2 && (
<>
<Grid data={cart}>
<GridColumn field="name" title="Item" />
<GridColumn field="price" title="Price" cell={(props) => <td>${props.dataItem.price}</td>} />
<GridColumn field="quantity" title="Qty" />
</Grid>
<p>Total: ${(cart.reduce((sum, item) => sum + item.price * item.quantity, 0) * (1 - discount / 100)).toFixed(2)}</p>
</>
)}
<ButtonGroup>
{checkoutStep > 0 && <Button onClick={() => setCheckoutStep(checkoutStep - 1)}>Previous</Button>}
<Button onClick={handleCheckout}>{checkoutStep === 2 ? 'Place Order' : 'Next'}</Button>
</ButtonGroup>
</>
)}
</Dialog>
)}
{showOrderHistory && (
<Dialog title="Order History" onClose={() => setShowOrderHistory(false)} width={700}>
<Grid data={orderHistory}>
<GridColumn field="id" title="Order #" />
<GridColumn field="date" title="Date" />
<GridColumn field="total" title="Total" />
<GridColumn field="status" title="Status" />
</Grid>
</Dialog>
)}
{showContactForm && (
<Dialog title="Contact Us" onClose={() => setShowContactForm(false)}>
<StackLayout gap={10}>
<Input placeholder="Name" value={contactForm.name} onChange={(e) => setContactForm({ ...contactForm, name: e.value })} />
<Input placeholder="Email" value={contactForm.email} onChange={(e) => setContactForm({ ...contactForm, email: e.value })} />
<TextArea placeholder="Message" value={contactForm.message} onChange={(e) => setContactForm({ ...contactForm, message: e.value })} />
<Button onClick={() => alert('Message Sent!')}>Send</Button>
</StackLayout>
</Dialog>
)}
{showWishlist && (
<Dialog title="Wishlist" onClose={() => setShowWishlist(false)}>
<Grid data={wishlist}>
<GridColumn field="name" title="Name" />
<GridColumn field="price" title="Price" cell={(props) => <td>${props.dataItem.price}</td>} />
<GridColumn
title="Actions"
cell={(props) => <td><Button onClick={() => handleAddToCart(props.dataItem)}>Add to Cart</Button></td>}
/>
</Grid>
</Dialog>
)}
{/* Notification */}
{showNotification && (
<Notification type={{ style: 'success', icon: true }} closable={true}>
{checkoutStep === 2 ? 'Order placed!' : 'Added to cart!'}
</Notification>
)}
{/* Massive Additional Content */}
<Menu>
<MenuItem text="Shop More" icon="shop">
<MenuItem text="New Arrivals" />
<MenuItem text="Best Sellers" />
</MenuItem>
<MenuItem text="Support" icon="help" />
</Menu>
{Array.from({ length: 20 }, (_, i) => (
<ExpansionPanel key={i} title={`Collection ${i + 1}`}>
<GridLayout cols={[{ width: '33%' }, { width: '33%' }, { width: '33%' }]}>
{products.slice(i * 5, i * 5 + 5).map((p) => (
<GridLayoutItem key={p.id}>
<Card>
<img src={p.image} alt={p.name} className="product-image" />
<p>{p.name}</p>
<p>${p.price}</p>
<Button onClick={() => handleAddToCart(p)}>Add</Button>
</Card>
</GridLayoutItem>
))}
</GridLayout>
</ExpansionPanel>
))}
<ProgressBar value={cart.length * 10} max={100} label="Cart Progress" />
{/* Bottom Navigation */}
<BottomNavigation>
<BottomNavigationItem icon="home" text="Home" />
<BottomNavigationItem icon="cart" text="Cart" onClick={() => setShowCheckout(true)} />
<BottomNavigationItem icon="user" text="Profile" onClick={() => setShowLogin(true)} />
</BottomNavigation>
{/* Footer */}
<footer className="footer">
<h3>Owner: Aniruddha Adak</h3>
<StackLayout gap={20} orientation="horizontal" className="social-links">
<a href="https://www.linkedin.com/in/aniruddha-adak" target="_blank" rel="noopener noreferrer">
<SvgIcon icon={linkedinIcon} size="large" />
</a>
<a href="https://github.com/AniruddhaAdak" target="_blank" rel="noopener noreferrer">
<SvgIcon icon={githubIcon} size="large" />
</a>
<a href="https://x.com/aniruddhadak" target="_blank" rel="noopener noreferrer">
<SvgIcon icon={twitterIcon} size="large" />
</a>
<a href="https://dev.to/aniruddhaadak" target="_blank" rel="noopener noreferrer">
<SvgIcon icon={globeIcon} size="large" />
</a>
<a href="https://aniruddha-adak.vercel.app" target="_blank" rel="noopener noreferrer">
<SvgIcon icon={userIcon} size="large" />
</a>
<a href="mailto:aniruddhaadak80@gmail.com">
<SvgIcon icon={emailIcon} size="large" />
</a>
</StackLayout>
<p>© 2025 Aniruddha Adak. All rights reserved.</p>
</footer>
</div>
</div>
);
}
export default App;
App.css
/* General Styles */
.App {
font-family: 'Roboto', Arial, sans-serif;
background: linear-gradient(135deg, #f0f4f8, #d9e2ec);
min-height: 100vh;
color: #333;
}
h1, h2, h3 {
color: #2c3e50;
}
.content {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
/* AppBar */
.appbar {
background: #2980b9 !important;
padding: 15px 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
.appbar-actions {
margin-left: auto;
}
/* Drawer */
.k-drawer {
background: #34495e;
color: white;
}
.k-drawer-item:hover {
background: #3e5f7e;
}
/* Promo Banner */
.promo-banner {
background: #f1c40f;
padding: 20px;
text-align: center;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}
/* Filters */
.filters {
background: #fff;
padding: 15px;
border-radius: 8px;
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.1);
flex-wrap: wrap;
}
/* Grid */
.product-grid {
background: #fff;
border-radius: 8px;
overflow-x: auto;
}
.k-grid th {
background: #3498db;
color: white;
}
.k-grid td {
border-bottom: 1px solid #ecf0f1;
}
/* Card */
.cart, .k-card {
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.1);
margin: 20px 0;
}
/* Dialog */
.k-dialog {
border-radius: 8px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
}
.checkout-steps {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.checkout-steps span {
padding: 8px 15px;
background: #ddd;
border-radius: 20px;
}
.checkout-steps .active {
background: #2980b9;
color: white;
}
/* Product Image */
.product-image {
width: 100%;
max-height: 250px;
object-fit: cover;
border-radius: 8px;
}
/* Footer */
.footer {
background: #2c3e50;
color: white;
padding: 40px 20px;
text-align: center;
margin-top: 40px;
border-top: 4px solid #3498db;
}
.social-links .k-svg-icon {
font-size: 32px !important;
color: #ecf0f1;
transition: color 0.3s;
}
.social-links .k-svg-icon:hover {
color: #3498db;
}
/* Responsive Design */
@media (max-width: 1024px) {
.content {
padding: 15px;
}
.filters {
flex-direction: column;
gap: 10px;
}
.k-grid {
font-size: 14px;
}
.k-dialog {
width: 90% !important;
}
}
@media (max-width: 768px) {
.appbar {
flex-direction: column;
align-items: flex-start;
padding: 10px;
}
.appbar-actions {
margin-top: 10px;
width: 100%;
justify-content: space-between;
}
.promo-banner {
padding: 15px;
}
.k-grid th, .k-grid td {
padding: 8px;
}
.footer {
padding: 20px;
}
.social-links {
flex-wrap: wrap;
gap: 15px;
}
}
@media (max-width: 480px) {
h1 { font-size: 20px; }
h2 { font-size: 18px; }
h3 { font-size: 16px; }
p { font-size: 12px; }
.filters {
padding: 10px;
}
.k-button {
padding: 6px 12px;
font-size: 12px;
}
.product-image {
max-height: 150px;
}
.social-links .k-svg-icon {
font-size: 24px !important;
}
}
Top comments (0)