add dress style component
This commit is contained in:
parent
cc8fac8f32
commit
0440f95abf
19 changed files with 227 additions and 3 deletions
|
|
@ -41,6 +41,7 @@ INSTALLED_APPS = [
|
||||||
"corsheaders",
|
"corsheaders",
|
||||||
"rest_framework",
|
"rest_framework",
|
||||||
"api",
|
"api",
|
||||||
|
"dressstyle",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,14 @@ from django.contrib import admin
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("admin/", admin.site.urls),
|
|
||||||
path("api/", include("api.urls")),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
path("admin/", admin.site.urls),
|
||||||
|
|
||||||
|
path("api/", include("api.urls")),
|
||||||
|
|
||||||
|
path("api/dress-styles/", include("dressstyle.urls")),
|
||||||
|
|
||||||
|
]
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
urlpatterns += static(
|
urlpatterns += static(
|
||||||
settings.MEDIA_URL,
|
settings.MEDIA_URL,
|
||||||
|
|
|
||||||
0
dressstyle/__init__.py
Normal file
0
dressstyle/__init__.py
Normal file
9
dressstyle/admin.py
Normal file
9
dressstyle/admin.py
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from .models import DressStyle
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(DressStyle)
|
||||||
|
class DressStyleAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('name', 'image')
|
||||||
|
search_fields = ('name',)
|
||||||
5
dressstyle/apps.py
Normal file
5
dressstyle/apps.py
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class DressstyleConfig(AppConfig):
|
||||||
|
name = 'dressstyle'
|
||||||
22
dressstyle/migrations/0001_initial.py
Normal file
22
dressstyle/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Generated by Django 6.1.1 on 2026-09-18 14:33
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='DressStyle',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=100)),
|
||||||
|
('image', models.ImageField(upload_to='dress_styles/')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
0
dressstyle/migrations/__init__.py
Normal file
0
dressstyle/migrations/__init__.py
Normal file
9
dressstyle/models.py
Normal file
9
dressstyle/models.py
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class DressStyle(models.Model):
|
||||||
|
name = models.CharField(max_length=100)
|
||||||
|
image = models.ImageField(upload_to='dress_styles/')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
9
dressstyle/serializers.py
Normal file
9
dressstyle/serializers.py
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from .models import DressStyle
|
||||||
|
|
||||||
|
|
||||||
|
class DressStyleSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = DressStyle
|
||||||
|
fields = ('id', 'name', 'image')
|
||||||
3
dressstyle/tests.py
Normal file
3
dressstyle/tests.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
8
dressstyle/urls.py
Normal file
8
dressstyle/urls.py
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from .views import DressStyleListView
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', DressStyleListView.as_view(), name='dressstyle-list'),
|
||||||
|
]
|
||||||
9
dressstyle/views.py
Normal file
9
dressstyle/views.py
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
from rest_framework import generics
|
||||||
|
|
||||||
|
from .models import DressStyle
|
||||||
|
from .serializers import DressStyleSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class DressStyleListView(generics.ListAPIView):
|
||||||
|
queryset = DressStyle.objects.all()
|
||||||
|
serializer_class = DressStyleSerializer
|
||||||
89
frontend/src/components/DressStyle/DressStyle.module.css
Normal file
89
frontend/src/components/DressStyle/DressStyle.module.css
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
.section {
|
||||||
|
width: calc(100% - 48px);
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 30px auto 0;
|
||||||
|
padding: 48px;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-radius: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section :global(.container) {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin: 0 0 30px;
|
||||||
|
color: #000;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1;
|
||||||
|
text-align: center;
|
||||||
|
letter-spacing: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.styles {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
height: 220px;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: #f1efef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover .image {
|
||||||
|
transform: scale(1.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
position: absolute;
|
||||||
|
left: 16px;
|
||||||
|
bottom: 16px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 10px 16px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
.section {
|
||||||
|
width: calc(100% - 24px);
|
||||||
|
padding: 32px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.styles {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
height: 180px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 420px) {
|
||||||
|
.section {
|
||||||
|
padding: 40px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
frontend/src/components/DressStyle/DressStyle.tsx
Normal file
53
frontend/src/components/DressStyle/DressStyle.tsx
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import styles from './DressStyle.module.css'
|
||||||
|
|
||||||
|
type DressStyleItem = {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
image: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function DressStyle() {
|
||||||
|
const [dressStyles, setDressStyles] = useState<DressStyleItem[]>([])
|
||||||
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('http://127.0.0.1:8000/api/dress-styles/')
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
setDressStyles(data)
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsLoading(false)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={styles.section}>
|
||||||
|
<div className="container">
|
||||||
|
<h2 className={styles.title}>BROWSE BY DRESS STYLE</h2>
|
||||||
|
|
||||||
|
<div className={styles.styles}>
|
||||||
|
{dressStyles.map((dressStyle) => (
|
||||||
|
<article key={dressStyle.id} className={styles.card}>
|
||||||
|
<img
|
||||||
|
src={dressStyle.image}
|
||||||
|
alt={dressStyle.name}
|
||||||
|
className={styles.image}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<h3 className={styles.name}>{dressStyle.name}</h3>
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DressStyle
|
||||||
|
|
@ -4,6 +4,7 @@ import Hero from '../../components/Hero/Hero'
|
||||||
import Brends from '../../components/Brends/Brends'
|
import Brends from '../../components/Brends/Brends'
|
||||||
import Arrivals from '../../components/NewArrivals/NewArrivals'
|
import Arrivals from '../../components/NewArrivals/NewArrivals'
|
||||||
import TopSelling from '../../components/TopSelling/TopSelling'
|
import TopSelling from '../../components/TopSelling/TopSelling'
|
||||||
|
import DressStyle from '../../components/DressStyle/DressStyle'
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -19,6 +20,8 @@ function Home() {
|
||||||
<Arrivals />
|
<Arrivals />
|
||||||
|
|
||||||
<TopSelling />
|
<TopSelling />
|
||||||
|
|
||||||
|
<DressStyle />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
media/dress_styles/dress_style_four.png
Normal file
BIN
media/dress_styles/dress_style_four.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
BIN
media/dress_styles/dress_style_one.png
Normal file
BIN
media/dress_styles/dress_style_one.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 91 KiB |
BIN
media/dress_styles/dress_style_three.png
Normal file
BIN
media/dress_styles/dress_style_three.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 206 KiB |
BIN
media/dress_styles/dress_style_two.png
Normal file
BIN
media/dress_styles/dress_style_two.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 190 KiB |
Loading…
Add table
Reference in a new issue