work on the frontend
This commit is contained in:
+167
-187
@@ -1,218 +1,198 @@
|
||||
I’m building a Laravel application (like ProductHunt) and need help implementing **Search & Filtering** for products. Here’s what I need:
|
||||
I’m **liquid sky**, building a Laravel application (like ProductHunt/Uneed.best) and need help with **frontend development**. Here’s what I need for a modern, responsive, and dynamic UI:
|
||||
|
||||
---
|
||||
|
||||
### **1. Database & Model Setup**
|
||||
- Assume the `products` table already exists with the following fields:
|
||||
- `title` (string)
|
||||
- `description` (text)
|
||||
- `status` (string: 'pending', 'approved', 'rejected')
|
||||
- `category_id` (foreign key)
|
||||
- `created_at` (timestamp)
|
||||
- Ensure the `Product` model has relationships for `category` and `user`.
|
||||
### **1. Tech Stack & Setup**
|
||||
- **Frontend Framework**: Use **Blade templates** with **Tailwind CSS** for styling.
|
||||
- **Dynamic Features**: Use **Alpine.js** for lightweight interactivity (e.g., toggles, modals).
|
||||
- **Real-Time Updates**: Use **Laravel Echo** (if real-time features are needed).
|
||||
- **Build Tool**: Use **Laravel Mix** or **Vite** for asset compilation.
|
||||
|
||||
---
|
||||
|
||||
### **2. Search Functionality**
|
||||
#### **A. Basic Search**
|
||||
- Implement a search feature to find products by `title` and `description`.
|
||||
- Use Laravel’s query builder to search for partial matches (e.g., `WHERE title LIKE %search_term% OR description LIKE %search_term%`).
|
||||
- Add a search form to the homepage (`products.index`):
|
||||
- Input field for the search term.
|
||||
- Submit button to trigger the search.
|
||||
- Display search results in the same view.
|
||||
### **2. UI/UX Design**
|
||||
#### **A. Core Pages**
|
||||
Design and implement the following pages with a clean, intuitive UI:
|
||||
1. **Homepage (`products.index`)**
|
||||
- Hero section with a search bar and trending products.
|
||||
- Grid/list view of products (filterable/sortable).
|
||||
- Sidebar for filters (categories, status, date range).
|
||||
- Pagination at the bottom.
|
||||
|
||||
#### **B. Advanced Search (Optional)**
|
||||
- Use **Laravel Scout** with **Algolia** or **Meilisearch** for full-text search (if basic search is insufficient).
|
||||
- Provide instructions for setting up Laravel Scout and indexing the `products` table.
|
||||
2. **Product Show Page (`products.show`)**
|
||||
- Product title, description, website link, and thumbnail.
|
||||
- Upvote button (with count), bookmark button, and share options.
|
||||
- Comments section (nested, with user avatars and timestamps).
|
||||
- Related products (based on category or tags).
|
||||
|
||||
3. **Product Submission Form (`products.create`)**
|
||||
- Form fields: title, description, website URL, category dropdown, thumbnail upload.
|
||||
- Real-time validation feedback (e.g., URL format, required fields).
|
||||
- Preview section for the thumbnail.
|
||||
|
||||
4. **User Profile Page (`profile.show`)**
|
||||
- User avatar, bio, and social links.
|
||||
- Tabs for: submitted products, upvoted products, bookmarked products.
|
||||
- Edit profile button (links to `profile.edit`).
|
||||
|
||||
5. **Admin Dashboard (`products.manage`)**
|
||||
- Table of all products with filters for status (pending/approved/rejected).
|
||||
- Actions: approve, reject, edit, delete.
|
||||
- Search bar to find products by title/description.
|
||||
|
||||
6. **Authentication Pages**
|
||||
- Login, registration, and password reset forms (use Laravel Breeze/Fortify scaffolding).
|
||||
|
||||
---
|
||||
|
||||
### **3. Filtering Functionality**
|
||||
#### **A. Category Filtering**
|
||||
- Add a dropdown or checkboxes to filter products by `category_id`.
|
||||
- Modify the query to include:
|
||||
```php
|
||||
\$products = Product::query()
|
||||
->when(request('category'), function (\$query) {
|
||||
\$query->where('category_id', request('category'));
|
||||
})
|
||||
->get();
|
||||
#### **B. UI Components**
|
||||
Create reusable Blade components for:
|
||||
1. **Navigation Bar**
|
||||
- Logo, search bar, user avatar dropdown (login/logout/profile).
|
||||
- Responsive design (collapses to hamburger menu on mobile).
|
||||
|
||||
2. **Product Card**
|
||||
- Thumbnail, title, description (truncated), upvote count, category tag.
|
||||
- Hover effects and responsive layout (grid on desktop, list on mobile).
|
||||
|
||||
3. **Upvote/Bookmark Buttons**
|
||||
- Interactive buttons with visual feedback (e.g., color change on click).
|
||||
- AJAX-powered to avoid page reloads.
|
||||
|
||||
4. **Comment Section**
|
||||
- Form to add a comment (authenticated users only).
|
||||
- Nested comments with user avatars, usernames, and timestamps.
|
||||
- Delete button for comment owners/admins.
|
||||
|
||||
5. **Modals**
|
||||
- Confirmation modals for actions like deleting a product/comment.
|
||||
- Image preview modal for thumbnails.
|
||||
|
||||
6. **Notifications**
|
||||
- Toast notifications for success/error messages (e.g., "Product submitted!").
|
||||
- Dropdown for in-app notifications (e.g., "Your product was approved").
|
||||
|
||||
---
|
||||
|
||||
### **3. Responsive Layouts**
|
||||
- Use **Tailwind CSS** for responsive design:
|
||||
- Mobile-first approach.
|
||||
- Breakpoints: `sm` (640px), `md` (768px), `lg` (1024px), `xl` (1280px).
|
||||
- Example:
|
||||
```html
|
||||
<div class="grid grid-cols-1 sm\:grid-cols-2 lg\:grid-cols-3 gap-4">
|
||||
<!-- Product cards -->
|
||||
</div>
|
||||
```
|
||||
- Test layouts on:
|
||||
- Mobile (iPhone SE, Galaxy S20).
|
||||
- Tablet (iPad, Surface).
|
||||
- Desktop (1024px and above).
|
||||
|
||||
---
|
||||
|
||||
### **4. Dynamic Features**
|
||||
#### **A. Upvoting & Bookmarking**
|
||||
- Use **Alpine.js** for client-side interactivity:
|
||||
```html
|
||||
<button
|
||||
x-data="{ upvoted: {{ \$product->isUpvotedBy(auth()->user()) ? 'true' : 'false' }} }"
|
||||
x-on\:click="
|
||||
fetch('{{ route('products.upvote', \$product) }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
upvoted = !upvoted;
|
||||
document.querySelector('.upvote-count').textContent = data.upvotesCount;
|
||||
});
|
||||
"
|
||||
\:class="{ 'text-green-500': upvoted, 'text-gray-500': !upvoted }"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7" />
|
||||
</svg>
|
||||
<span class="upvote-count">{{ \$product->upvotes->count() }}</span>
|
||||
</button>
|
||||
```
|
||||
#### **B. Real-Time Updates**
|
||||
|
||||
#### **B. Status Filtering**
|
||||
Use Laravel Echo to listen for events (e.g., ProductUpvoted, CommentCreated):
|
||||
|
||||
Add filters for product status (e.g., 'approved', 'pending').
|
||||
Example query:
|
||||
|
||||
```php
|
||||
\$products = Product::query()
|
||||
->when(request('status'), function (\$query) {
|
||||
\$query->where('status', request('status'));
|
||||
```
|
||||
Echo.channel('product.' + productId)
|
||||
.listen('ProductUpvoted', (e) => {
|
||||
document.querySelector('.upvote-count').textContent = e.upvotesCount;
|
||||
})
|
||||
->get();
|
||||
.listen('CommentCreated', (e) => {
|
||||
// Append new comment to the DOM
|
||||
const commentsContainer = document.querySelector('.comments-container');
|
||||
commentsContainer.innerHTML += `
|
||||
<div class="comment">
|
||||
<img src="\${e.comment.user.avatar}" class="w-8 h-8 rounded-full">
|
||||
<div>
|
||||
<p class="font-bold">${e.comment.user.name}</p>
|
||||
<p>${e.comment.body}</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
```
|
||||
|
||||
#### **C. Date Filtering**
|
||||
#### **C. Infinite Scroll**
|
||||
|
||||
Add filters for products created within a specific time range (e.g., 'Last Week', 'Last Month', 'All Time').
|
||||
Example query:
|
||||
Replace pagination with infinite scroll for the product grid:
|
||||
|
||||
```php
|
||||
\$products = Product::query()
|
||||
->when(request('date_range'), function (\$query) {
|
||||
\$query->where('created_at', '>=', now()->subDays(request('date_range')));
|
||||
})
|
||||
->get();
|
||||
```
|
||||
window.addEventListener('scroll', () => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
|
||||
if (scrollTop + clientHeight >= scrollHeight - 5) {
|
||||
// Fetch next page of products
|
||||
fetch(`/products?page=${currentPage + 1}`)
|
||||
.then(response => response.text())
|
||||
.then(html => {
|
||||
document.querySelector('.products-grid').innerHTML += html;
|
||||
currentPage++;
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### **D. Popularity Filtering**
|
||||
### **5. Accessibility & Performance**
|
||||
|
||||
Add a filter to sort products by upvote count (e.g., 'Most Popular').
|
||||
Example query:
|
||||
Accessibility:
|
||||
|
||||
```php
|
||||
\$products = Product::withCount('upvotes')
|
||||
->when(request('sort') === 'popular', function (\$query) {
|
||||
\$query->orderBy('upvotes_count', 'desc');
|
||||
})
|
||||
->get();
|
||||
```
|
||||
Use semantic HTML (<button>, <nav>, <article>).
|
||||
Add ARIA attributes for dynamic elements (e.g., aria-live for notifications).
|
||||
Ensure keyboard navigability (e.g., tab index for modals).
|
||||
|
||||
### **4. Combined Search & Filtering**
|
||||
Performance:
|
||||
|
||||
Combine search and filtering in a single query:
|
||||
Lazy-load images (use loading="lazy" for thumbnails).
|
||||
Minify CSS/JS with Laravel Mix/Vite.
|
||||
Use defer for non-critical JS.
|
||||
|
||||
```php
|
||||
\$products = Product::query()
|
||||
->when(request('search'), function (\$query) {
|
||||
\$query->where(function (\$subQuery) {
|
||||
\$subQuery->where('title', 'like', '%' . request('search') . '%')
|
||||
->orWhere('description', 'like', '%' . request('search') . '%');
|
||||
});
|
||||
})
|
||||
->when(request('category'), function (\$query) {
|
||||
\$query->where('category_id', request('category'));
|
||||
})
|
||||
->when(request('status'), function (\$query) {
|
||||
\$query->where('status', request('status'));
|
||||
})
|
||||
->when(request('sort') === 'popular', function (\$query) {
|
||||
\$query->withCount('upvotes')->orderBy('upvotes_count', 'desc');
|
||||
})
|
||||
->paginate(10);
|
||||
```
|
||||
|
||||
### **5. Frontend Implementation**
|
||||
#### **A. Search & Filter Form**
|
||||
### **6. Example Code Snippets**
|
||||
Include the following in your response:
|
||||
|
||||
Create a Blade view (products.index) with:
|
||||
|
||||
Search input field (bound to request('search')).
|
||||
Category dropdown (populated from the categories table).
|
||||
Status filter (radio buttons or dropdown).
|
||||
Date range filter (dropdown with options: 'Last Week', 'Last Month', 'All Time').
|
||||
Sorting options (e.g., 'Newest', 'Most Popular').
|
||||
|
||||
#### **B. Example Blade Snippet**
|
||||
|
||||
```html
|
||||
<form method="GET" action="{{ route('products.index') }}" class="mb-4">
|
||||
<div class="flex gap-4 items-end">
|
||||
<div class="flex-1">
|
||||
<label for="search" class="block text-sm font-medium text-gray-700">Search</label>
|
||||
<input
|
||||
type="text"
|
||||
name="search"
|
||||
id="search"
|
||||
value="{{ request('search') }}"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
|
||||
placeholder="Search products..."
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="category" class="block text-sm font-medium text-gray-700">Category</label>
|
||||
<select name="category" id="category" class="mt-1 block rounded-md border-gray-300 shadow-sm">
|
||||
<option value="">All Categories</option>
|
||||
@foreach(\$categories as \$category)
|
||||
<option value="{{ \$category->id }}" {{ request('category') == \$category->id ? 'selected' : '' }}>
|
||||
{{ \$category->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="sort" class="block text-sm font-medium text-gray-700">Sort By</label>
|
||||
<select name="sort" id="sort" class="mt-1 block rounded-md border-gray-300 shadow-sm">
|
||||
<option value="newest" {{ request('sort') === 'newest' ? 'selected' : '' }}>Newest</option>
|
||||
<option value="popular" {{ request('sort') === 'popular' ? 'selected' : '' }}>Most Popular</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-md hover\:bg-blue-700">
|
||||
Apply Filters
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
```
|
||||
|
||||
#### **C. Displaying Results**
|
||||
|
||||
Loop through the paginated results and display each product:
|
||||
|
||||
```php
|
||||
@forelse(\$products as \$product)
|
||||
<div class="border rounded-lg p-4 mb-4">
|
||||
<h3 class="font-bold text-lg">{{ \$product->title }}</h3>
|
||||
<p class="text-gray-600">{{ Str::limit(\$product->description, 100) }}</p>
|
||||
<div class="flex items-center gap-2 mt-2">
|
||||
<span class="text-sm text-gray-500">{{ \$product->category->name }}</span>
|
||||
<span class="text-sm text-gray-500">{{ \$product->upvotes_count }} upvotes</span>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-gray-500">No products found.</p>
|
||||
@endforelse
|
||||
|
||||
{{ \$products->appends(request()->query())->links() }}
|
||||
```
|
||||
|
||||
### **6. Pagination**
|
||||
|
||||
Use Laravel’s built-in pagination:
|
||||
|
||||
```php
|
||||
\$products = \$products->paginate(10)->appends(request()->query());
|
||||
```
|
||||
Display pagination links in the Blade view (as shown above).
|
||||
Blade layout (layouts.app) with navigation bar and footer.
|
||||
Product card component (reusable Blade component).
|
||||
Product show page with upvote/comment sections.
|
||||
Alpine.js examples for interactive elements (e.g., modals, toggles).
|
||||
Laravel Echo setup for real-time updates.
|
||||
Responsive grid for product listings.
|
||||
Tailwind CSS configuration (if customizing themes/colors).
|
||||
|
||||
### **7. Testing**
|
||||
|
||||
Write tests for:
|
||||
Test the frontend for:
|
||||
|
||||
Search functionality (partial matches for title/description).
|
||||
Category filtering.
|
||||
Status filtering.
|
||||
Date range filtering.
|
||||
Popularity sorting.
|
||||
Pagination.
|
||||
|
||||
|
||||
### **8. Example Code Snippets**
|
||||
Include the following in your response:
|
||||
|
||||
Combined search & filtering query (as shown above).
|
||||
Blade view for the search/filter form.
|
||||
Blade view for displaying results and pagination.
|
||||
Controller method for handling the search/filter request.
|
||||
Test cases for search and filtering.
|
||||
|
||||
### **Notes:**
|
||||
|
||||
Use Laravel’s query builder for basic search/filtering.
|
||||
Use Laravel Scout for advanced full-text search (optional).
|
||||
Assume Tailwind CSS for styling.
|
||||
Ensure filters are preserved during pagination (use appends(request()->query())).
|
||||
Optimize queries with withCount('upvotes') to avoid N+1 issues.
|
||||
Cross-browser compatibility (Chrome, Firefox, Safari, Edge).
|
||||
Responsive breakpoints (use Chrome DevTools).
|
||||
Accessibility (use Lighthouse or axe).
|
||||
Performance (Lighthouse score > 90).
|
||||
|
||||
Reference in New Issue
Block a user