diff --git a/backend/settings.py b/backend/settings.py index 9083ced..2fd54a6 100644 --- a/backend/settings.py +++ b/backend/settings.py @@ -41,6 +41,7 @@ INSTALLED_APPS = [ "corsheaders", "rest_framework", "api", + "dressstyle", ] MIDDLEWARE = [ diff --git a/backend/urls.py b/backend/urls.py index 94464d3..34b6873 100644 --- a/backend/urls.py +++ b/backend/urls.py @@ -4,10 +4,14 @@ from django.contrib import admin from django.urls import include, path 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: urlpatterns += static( settings.MEDIA_URL, diff --git a/dressstyle/__init__.py b/dressstyle/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dressstyle/admin.py b/dressstyle/admin.py new file mode 100644 index 0000000..53b4aa9 --- /dev/null +++ b/dressstyle/admin.py @@ -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',) \ No newline at end of file diff --git a/dressstyle/apps.py b/dressstyle/apps.py new file mode 100644 index 0000000..786c58c --- /dev/null +++ b/dressstyle/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class DressstyleConfig(AppConfig): + name = 'dressstyle' diff --git a/dressstyle/migrations/0001_initial.py b/dressstyle/migrations/0001_initial.py new file mode 100644 index 0000000..835c75a --- /dev/null +++ b/dressstyle/migrations/0001_initial.py @@ -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/')), + ], + ), + ] diff --git a/dressstyle/migrations/__init__.py b/dressstyle/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dressstyle/models.py b/dressstyle/models.py new file mode 100644 index 0000000..657e70a --- /dev/null +++ b/dressstyle/models.py @@ -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 \ No newline at end of file diff --git a/dressstyle/serializers.py b/dressstyle/serializers.py new file mode 100644 index 0000000..c55150b --- /dev/null +++ b/dressstyle/serializers.py @@ -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') \ No newline at end of file diff --git a/dressstyle/tests.py b/dressstyle/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/dressstyle/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/dressstyle/urls.py b/dressstyle/urls.py new file mode 100644 index 0000000..8d0ebfb --- /dev/null +++ b/dressstyle/urls.py @@ -0,0 +1,8 @@ +from django.urls import path + +from .views import DressStyleListView + + +urlpatterns = [ + path('', DressStyleListView.as_view(), name='dressstyle-list'), +] \ No newline at end of file diff --git a/dressstyle/views.py b/dressstyle/views.py new file mode 100644 index 0000000..9d5c8d2 --- /dev/null +++ b/dressstyle/views.py @@ -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 \ No newline at end of file diff --git a/frontend/src/components/DressStyle/DressStyle.module.css b/frontend/src/components/DressStyle/DressStyle.module.css new file mode 100644 index 0000000..dd819d1 --- /dev/null +++ b/frontend/src/components/DressStyle/DressStyle.module.css @@ -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; + } +} \ No newline at end of file diff --git a/frontend/src/components/DressStyle/DressStyle.tsx b/frontend/src/components/DressStyle/DressStyle.tsx new file mode 100644 index 0000000..18d20c1 --- /dev/null +++ b/frontend/src/components/DressStyle/DressStyle.tsx @@ -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([]) + 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 ( +
+
+

BROWSE BY DRESS STYLE

+ +
+ {dressStyles.map((dressStyle) => ( +
+ {dressStyle.name} + +

{dressStyle.name}

+
+ ))} +
+
+
+ ) +} + +export default DressStyle \ No newline at end of file diff --git a/frontend/src/pages/Home/Home.tsx b/frontend/src/pages/Home/Home.tsx index d4e62b7..419f738 100644 --- a/frontend/src/pages/Home/Home.tsx +++ b/frontend/src/pages/Home/Home.tsx @@ -4,6 +4,7 @@ import Hero from '../../components/Hero/Hero' import Brends from '../../components/Brends/Brends' import Arrivals from '../../components/NewArrivals/NewArrivals' import TopSelling from '../../components/TopSelling/TopSelling' +import DressStyle from '../../components/DressStyle/DressStyle' function Home() { return ( @@ -19,6 +20,8 @@ function Home() { + + ) } diff --git a/media/dress_styles/dress_style_four.png b/media/dress_styles/dress_style_four.png new file mode 100644 index 0000000..80bd648 Binary files /dev/null and b/media/dress_styles/dress_style_four.png differ diff --git a/media/dress_styles/dress_style_one.png b/media/dress_styles/dress_style_one.png new file mode 100644 index 0000000..709d20b Binary files /dev/null and b/media/dress_styles/dress_style_one.png differ diff --git a/media/dress_styles/dress_style_three.png b/media/dress_styles/dress_style_three.png new file mode 100644 index 0000000..7f0dfc9 Binary files /dev/null and b/media/dress_styles/dress_style_three.png differ diff --git a/media/dress_styles/dress_style_two.png b/media/dress_styles/dress_style_two.png new file mode 100644 index 0000000..91be778 Binary files /dev/null and b/media/dress_styles/dress_style_two.png differ