웹 메인페이지 레이아웃 UI 추가
This commit is contained in:
parent
95053c2e00
commit
8829bcd025
53
app/Http/Controllers/Admin/Auth/AdminAuthController.php
Normal file
53
app/Http/Controllers/Admin/Auth/AdminAuthController.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
class AdminAuthController extends Controller
|
||||||
|
{
|
||||||
|
// 로그인 폼
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
return view('admin.auth.login');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 로그인 처리
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$credentials = $request->validate([
|
||||||
|
'email' => ['required', 'email'],
|
||||||
|
'password' => ['required', 'string'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// remember 체크박스 지원 (선택)
|
||||||
|
$remember = $request->boolean('remember');
|
||||||
|
|
||||||
|
// 핵심: admin guard로 로그인 시도
|
||||||
|
if (! Auth::guard('admin')->attempt($credentials, $remember)) {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'email' => ['이메일 또는 비밀번호가 올바르지 않습니다.'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 세션 고정 공격 방지
|
||||||
|
$request->session()->regenerate();
|
||||||
|
|
||||||
|
return redirect()->route('admin.home');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 로그아웃 처리
|
||||||
|
public function destroy(Request $request)
|
||||||
|
{
|
||||||
|
Auth::guard('admin')->logout();
|
||||||
|
|
||||||
|
// 세션 무효화 + CSRF 토큰 재발급
|
||||||
|
$request->session()->invalidate();
|
||||||
|
$request->session()->regenerateToken();
|
||||||
|
|
||||||
|
return redirect()->route('admin.login');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,7 +14,7 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
then: function () {
|
then: function () {
|
||||||
Route::middleware('web')
|
Route::middleware('web')
|
||||||
->domain('four.syye.net')
|
->domain('four.syye.net')
|
||||||
->group(base_path('routes/site.php'));
|
->group(base_path('routes/web.php'));
|
||||||
|
|
||||||
Route::middleware('web')
|
Route::middleware('web')
|
||||||
->domain('shot.syye.net')
|
->domain('shot.syye.net')
|
||||||
|
|||||||
28
database/seeders/AdminUserSeeder.php
Normal file
28
database/seeders/AdminUserSeeder.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\AdminUser;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
|
class AdminUserSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
AdminUser::updateOrCreate(
|
||||||
|
['email' => 'admin@syye.net'],
|
||||||
|
[
|
||||||
|
'password' => Hash::make('tjekdfl1234%^'),
|
||||||
|
'full_name' => '최고관리자',
|
||||||
|
'nickname' => 'superadmin',
|
||||||
|
'phone' => null,
|
||||||
|
'role' => 'super',
|
||||||
|
'status' => 'active',
|
||||||
|
'is_consult_available' => true,
|
||||||
|
'consult_types' => ['signup','login','payment','giftcard','event'],
|
||||||
|
'totp_enabled' => false,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
2423
package-lock.json
generated
Normal file
2423
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
BIN
public/assets/fonts/pretendard/PretendardVariable.woff2
Normal file
BIN
public/assets/fonts/pretendard/PretendardVariable.woff2
Normal file
Binary file not shown.
15
public/css/pretendard.css
Normal file
15
public/css/pretendard.css
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "Pretendard";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 45 920; /* variable font range */
|
||||||
|
font-display: swap;
|
||||||
|
src: url("/assets/fonts/pretendard/PretendardVariable.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--font-sans: "Pretendard", system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans KR", Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
}
|
||||||
528
resources/css/web.css
Normal file
528
resources/css/web.css
Normal file
@ -0,0 +1,528 @@
|
|||||||
|
/* =========================================
|
||||||
|
Voucher Mall Design System
|
||||||
|
Theme: White base + Blue accent
|
||||||
|
========================================= */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* Colors */
|
||||||
|
--color-bg-base: #FFFFFF;
|
||||||
|
--color-bg-section: #F7F8FA; /* Very light grey for separation */
|
||||||
|
--color-bg-tint: #EFF6FF; /* Blue tint for badges */
|
||||||
|
|
||||||
|
--color-text-primary: #111827;
|
||||||
|
--color-text-secondary: #6B7280;
|
||||||
|
--color-text-tertiary: #9CA3AF;
|
||||||
|
--color-text-white: #FFFFFF;
|
||||||
|
|
||||||
|
--color-border: #E5E7EB;
|
||||||
|
|
||||||
|
--color-accent-blue: #2563EB;
|
||||||
|
--color-accent-blue-hover: #1D4ED8;
|
||||||
|
|
||||||
|
--color-footer-bg: #0B1220;
|
||||||
|
--color-footer-text: #E5E7EB;
|
||||||
|
|
||||||
|
/* Semantic */
|
||||||
|
--color-danger: #EF4444;
|
||||||
|
|
||||||
|
/* Spacing & Layout */
|
||||||
|
--container-width: 1280px;
|
||||||
|
--header-height-desktop: 72px;
|
||||||
|
--header-height-scroll: 56px;
|
||||||
|
|
||||||
|
/* Radius */
|
||||||
|
--radius-card: 16px;
|
||||||
|
--radius-pill: 9999px;
|
||||||
|
--radius-sm: 8px;
|
||||||
|
|
||||||
|
/* Shadows */
|
||||||
|
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||||
|
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||||
|
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
/* Transitions */
|
||||||
|
--transition-base: 200ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Base & Reset */
|
||||||
|
*, *::before, *::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, system-ui, Roboto, 'Helvetica Neue', 'Segoe UI', 'Apple SD Gothic Neo', 'Malgun Gothic', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', sans-serif;
|
||||||
|
background-color: var(--color-bg-base);
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
line-height: 1.5;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
transition: color var(--transition-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul, li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-family: inherit;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sr-only {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Typography */
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-h1 { font-size: 32px; line-height: 40px; }
|
||||||
|
.text-h2 { font-size: 22px; line-height: 28px; font-weight: 600; }
|
||||||
|
.text-body { font-size: 16px; }
|
||||||
|
.text-sm { font-size: 14px; }
|
||||||
|
.text-xs { font-size: 12px; }
|
||||||
|
|
||||||
|
/* Layout Utilities */
|
||||||
|
.container {
|
||||||
|
max-width: var(--container-width);
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-cols-12 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(12, 1fr);
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flex Utilities */
|
||||||
|
.flex { display: flex; }
|
||||||
|
.flex-col { flex-direction: column; }
|
||||||
|
.items-center { align-items: center; }
|
||||||
|
.justify-center { justify-content: center; }
|
||||||
|
.justify-between { justify-content: space-between; }
|
||||||
|
.gap-1 { gap: 4px; }
|
||||||
|
.gap-2 { gap: 8px; }
|
||||||
|
.gap-3 { gap: 12px; }
|
||||||
|
.gap-4 { gap: 16px; }
|
||||||
|
|
||||||
|
/* Components */
|
||||||
|
|
||||||
|
/* Buttons */
|
||||||
|
.btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: var(--radius-pill);
|
||||||
|
font-weight: 600;
|
||||||
|
transition: all var(--transition-base);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: var(--color-accent-blue);
|
||||||
|
color: white;
|
||||||
|
padding: 12px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: var(--color-accent-blue-hover);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-ghost {
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-ghost:hover {
|
||||||
|
color: var(--color-accent-blue);
|
||||||
|
background-color: var(--color-bg-tint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
.site-header {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 50;
|
||||||
|
background-color: rgba(255, 255, 255, 0.95);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
height: var(--header-height-desktop);
|
||||||
|
transition: height 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-header.scrolled {
|
||||||
|
height: var(--header-height-scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link:hover {
|
||||||
|
color: var(--color-accent-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
position: relative;
|
||||||
|
max-width: 520px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 44px;
|
||||||
|
padding: 0 48px 0 20px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--radius-pill);
|
||||||
|
background-color: #F3F4F6;
|
||||||
|
font-size: 15px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-accent-blue);
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0 0 0 2px var(--color-bg-tint);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 16px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hero Carousel */
|
||||||
|
.hero-slider {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 400px;
|
||||||
|
background-color: var(--color-bg-section);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-track {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
transition: transform 0.5s cubic-bezier(0.25, 1, 0.5, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-slide {
|
||||||
|
min-width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-content {
|
||||||
|
max-width: 1000px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-title {
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: 800;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-desc {
|
||||||
|
font-size: 18px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dots-container {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 24px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: rgba(0,0,0,0.2);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot.active {
|
||||||
|
background-color: var(--color-accent-blue);
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quick Categories */
|
||||||
|
.category-chips {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 32px 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
scrollbar-width: none; /* Firefox */
|
||||||
|
}
|
||||||
|
.category-chips::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--radius-pill);
|
||||||
|
white-space: nowrap;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 15px;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
background-color: white;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip:hover {
|
||||||
|
border-color: var(--color-accent-blue);
|
||||||
|
background-color: var(--color-bg-tint);
|
||||||
|
color: var(--color-accent-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Product Card */
|
||||||
|
.product-card {
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--radius-card);
|
||||||
|
overflow: hidden;
|
||||||
|
background: white;
|
||||||
|
transition: all 0.2s ease-out;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
border-color: #BFDBFE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-thumb {
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
background-color: #F3F4F6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: 16px;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
height: 48px; /* Fixed for 2 lines */
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-price-area {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discount {
|
||||||
|
color: var(--color-accent-blue);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.original-price {
|
||||||
|
text-decoration: line-through;
|
||||||
|
color: var(--color-text-tertiary);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-badge {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
background-color: var(--color-bg-tint);
|
||||||
|
color: var(--color-accent-blue);
|
||||||
|
border: 1px solid #DBEAFE;
|
||||||
|
border-radius: var(--radius-pill);
|
||||||
|
margin-top: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections */
|
||||||
|
.section {
|
||||||
|
padding: 60px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-end;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title h2 {
|
||||||
|
font-size: 28px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title p {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Snap Carousel (Monthly Deals) */
|
||||||
|
.snap-carousel {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
overflow-x: auto;
|
||||||
|
scroll-snap-type: x mandatory;
|
||||||
|
padding-bottom: 24px; /* for shadow */
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.snap-carousel::-webkit-scrollbar { display: none; }
|
||||||
|
|
||||||
|
.snap-item {
|
||||||
|
scroll-snap-align: start;
|
||||||
|
flex: 0 0 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Filter Tabs */
|
||||||
|
.filter-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--radius-pill);
|
||||||
|
background: white;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.18s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn.active {
|
||||||
|
background-color: var(--color-accent-blue);
|
||||||
|
color: white;
|
||||||
|
border-color: var(--color-accent-blue);
|
||||||
|
box-shadow: 0 2px 4px rgba(37, 99, 235, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn:hover:not(.active) {
|
||||||
|
background-color: #F9FAFB;
|
||||||
|
border-color: #D1D5DB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
.site-footer {
|
||||||
|
background-color: var(--color-footer-bg);
|
||||||
|
color: var(--color-footer-text);
|
||||||
|
padding: 60px 0 40px;
|
||||||
|
margin-top: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-link {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #9CA3AF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-link:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile Breakpoint */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
:root {
|
||||||
|
--header-height-desktop: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-cols-12 {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-title { font-size: 28px; }
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
display: none; /* Handle mobile search differently */
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-chips, .snap-carousel {
|
||||||
|
margin-right: -24px;
|
||||||
|
padding-right: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
129
resources/js/web.js
Normal file
129
resources/js/web.js
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
|
// --- Hero Carousel Logic ---
|
||||||
|
const heroTrack = document.querySelector('.hero-track');
|
||||||
|
const heroSlides = document.querySelectorAll('.hero-slide');
|
||||||
|
const preventBtn = document.querySelector('.slider-arrow.prev');
|
||||||
|
const nextBtn = document.querySelector('.slider-arrow.next');
|
||||||
|
const dots = document.querySelectorAll('.dot');
|
||||||
|
|
||||||
|
let currentSlide = 0;
|
||||||
|
const totalSlides = heroSlides.length;
|
||||||
|
let autoplayInterval;
|
||||||
|
|
||||||
|
function updateCarousel() {
|
||||||
|
heroTrack.style.transform = `translateX(-${currentSlide * 100}%)`;
|
||||||
|
dots.forEach((dot, index) => {
|
||||||
|
dot.classList.toggle('active', index === currentSlide);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextSlide() {
|
||||||
|
currentSlide = (currentSlide + 1) % totalSlides;
|
||||||
|
updateCarousel();
|
||||||
|
}
|
||||||
|
|
||||||
|
function prevSlide() {
|
||||||
|
currentSlide = (currentSlide - 1 + totalSlides) % totalSlides;
|
||||||
|
updateCarousel();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Controls
|
||||||
|
if(nextBtn) nextBtn.addEventListener('click', () => {
|
||||||
|
nextSlide();
|
||||||
|
resetAutoplay();
|
||||||
|
});
|
||||||
|
|
||||||
|
if(preventBtn) preventBtn.addEventListener('click', () => {
|
||||||
|
prevSlide();
|
||||||
|
resetAutoplay();
|
||||||
|
});
|
||||||
|
|
||||||
|
dots.forEach((dot, index) => {
|
||||||
|
dot.addEventListener('click', () => {
|
||||||
|
currentSlide = index;
|
||||||
|
updateCarousel();
|
||||||
|
resetAutoplay();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Autoplay
|
||||||
|
function startAutoplay() {
|
||||||
|
autoplayInterval = setInterval(nextSlide, 6000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetAutoplay() {
|
||||||
|
clearInterval(autoplayInterval);
|
||||||
|
startAutoplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hover pause
|
||||||
|
const heroSlider = document.querySelector('.hero-slider');
|
||||||
|
if (heroSlider) {
|
||||||
|
heroSlider.addEventListener('mouseenter', () => clearInterval(autoplayInterval));
|
||||||
|
heroSlider.addEventListener('mouseleave', startAutoplay);
|
||||||
|
startAutoplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- Header Scroll Effect ---
|
||||||
|
const header = document.querySelector('.site-header');
|
||||||
|
window.addEventListener('scroll', () => {
|
||||||
|
if (window.scrollY > 50) {
|
||||||
|
header.classList.add('scrolled');
|
||||||
|
} else {
|
||||||
|
header.classList.remove('scrolled');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// --- Filter Tabs Logic (Client-side simulation) ---
|
||||||
|
const tabBtns = document.querySelectorAll('.tab-btn');
|
||||||
|
const productGrid = document.querySelector('.product-grid-container');
|
||||||
|
const productItems = document.querySelectorAll('.product-item');
|
||||||
|
|
||||||
|
tabBtns.forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
// Active State
|
||||||
|
tabBtns.forEach(b => {
|
||||||
|
b.classList.remove('active');
|
||||||
|
b.setAttribute('aria-selected', 'false');
|
||||||
|
});
|
||||||
|
btn.classList.add('active');
|
||||||
|
btn.setAttribute('aria-selected', 'true');
|
||||||
|
|
||||||
|
// Filter Logic
|
||||||
|
const filter = btn.dataset.filter;
|
||||||
|
|
||||||
|
// Animation: Fade out
|
||||||
|
productGrid.style.opacity = '0';
|
||||||
|
productGrid.style.transform = 'translateY(10px)';
|
||||||
|
productGrid.style.transition = 'all 0.2s';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
productItems.forEach(item => {
|
||||||
|
if (filter === 'all' || item.dataset.category === filter) {
|
||||||
|
item.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
item.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fade in
|
||||||
|
productGrid.style.opacity = '1';
|
||||||
|
productGrid.style.transform = 'translateY(0)';
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Mobile Menu Toggle ---
|
||||||
|
const mobileMenuBtn = document.querySelector('.mobile-menu-btn');
|
||||||
|
// In a real implementation, we would toggle a drawer here.
|
||||||
|
// For this prototype, we'll just log it or alert.
|
||||||
|
if(mobileMenuBtn) {
|
||||||
|
mobileMenuBtn.addEventListener('click', () => {
|
||||||
|
alert('모바일 메뉴 드로어 열림 (구현 예정)');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
46
resources/views/admin/auth/login.blade.php
Normal file
46
resources/views/admin/auth/login.blade.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>관리자 로그인</title>
|
||||||
|
</head>
|
||||||
|
<body style="font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; max-width: 360px; margin: 80px auto;">
|
||||||
|
<h2>관리자 로그인</h2>
|
||||||
|
|
||||||
|
@if ($errors->any())
|
||||||
|
<div style="background:#ffecec; border:1px solid #ffb3b3; padding:10px; margin:12px 0;">
|
||||||
|
<ul style="margin:0; padding-left:18px;">
|
||||||
|
@foreach ($errors->all() as $error)
|
||||||
|
<li>{{ $error }}</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('admin.login.store') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div style="margin: 12px 0;">
|
||||||
|
<label>Email</label><br>
|
||||||
|
<input type="email" name="email" value="{{ old('email') }}" required autofocus
|
||||||
|
style="width:100%; padding:10px; box-sizing:border-box;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin: 12px 0;">
|
||||||
|
<label>Password</label><br>
|
||||||
|
<input type="password" name="password" required
|
||||||
|
style="width:100%; padding:10px; box-sizing:border-box;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin: 12px 0;">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="remember" value="1">
|
||||||
|
로그인 유지
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" style="width:100%; padding:10px;">로그인</button>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
20
resources/views/admin/home.blade.php
Normal file
20
resources/views/admin/home.blade.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>관리자 홈</title>
|
||||||
|
</head>
|
||||||
|
<body style="font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; max-width: 640px; margin: 60px auto;">
|
||||||
|
<h2>관리자 홈</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
로그인 사용자: {{ auth('admin')->user()->nickname }} ({{ auth('admin')->user()->email }})
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('admin.logout') }}">
|
||||||
|
@csrf
|
||||||
|
<button type="submit">로그아웃</button>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
38
resources/views/web/company/footer.blade.php
Normal file
38
resources/views/web/company/footer.blade.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<footer class="site-footer">
|
||||||
|
<div class="container footer-grid">
|
||||||
|
<!-- Col 1: Brand -->
|
||||||
|
<div>
|
||||||
|
<div style="font-size: 20px; font-weight: 700; color: white; margin-bottom: 16px;">GIFTICON</div>
|
||||||
|
<p style="font-size: 14px; color: #9CA3AF; line-height: 1.6;">
|
||||||
|
대한민국 1등 상품권 거래소.<br>
|
||||||
|
안전하고 빠른 거래를 약속드립니다.
|
||||||
|
</p>
|
||||||
|
<div style="margin-top: 24px; font-size: 12px; color: #6B7280;">
|
||||||
|
© 2024 Gifticon Corp. All rights reserved.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Col 2: Links -->
|
||||||
|
<div>
|
||||||
|
<h4 style="color: white; margin-bottom: 20px;">고객지원</h4>
|
||||||
|
<a href="#" class="footer-link">공지사항</a>
|
||||||
|
<a href="#" class="footer-link">자주 묻는 질문</a>
|
||||||
|
<a href="#" class="footer-link">1:1 문의</a>
|
||||||
|
<a href="#" class="footer-link">이용약관</a>
|
||||||
|
<a href="#" class="footer-link" style="font-weight: 600;">개인정보처리방침</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Col 3: Contact -->
|
||||||
|
<div>
|
||||||
|
<h4 style="color: white; margin-bottom: 20px;">Contact</h4>
|
||||||
|
<p style="margin-bottom: 8px;">고객센터: 1544-0000</p>
|
||||||
|
<p style="margin-bottom: 8px;">운영시간: 평일 09:00 - 18:00</p>
|
||||||
|
<p style="margin-bottom: 24px;">이메일: help@gifticon.com</p>
|
||||||
|
|
||||||
|
<div style="padding: 12px; background: rgba(255,255,255,0.05); border-radius: 8px;">
|
||||||
|
<p style="font-size: 12px; color: #9CA3AF; margin-bottom: 4px;">구매안전 서비스</p>
|
||||||
|
<p style="font-size: 13px; color: white;">KG Inicis 에스크로 적용됨</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
64
resources/views/web/company/header.blade.php
Normal file
64
resources/views/web/company/header.blade.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<header class="site-header">
|
||||||
|
<div class="container" style="height: 100%; display: flex; align-items: center; justify-content: space-between;">
|
||||||
|
|
||||||
|
<!-- Left: Logo & Nav -->
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<a href="/" class="logo"
|
||||||
|
style="font-size: 24px; font-weight: 800; color: var(--color-accent-blue); margin-right: 32px;">
|
||||||
|
GIFTICON
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<nav class="desktop-nav" style="display: flex; gap: 24px;">
|
||||||
|
<a href="/" class="nav-link">Home</a>
|
||||||
|
<a href="/shop" class="nav-link">Shop</a>
|
||||||
|
<a href="/exchange" class="nav-link">상품권현금교환</a>
|
||||||
|
<a href="/mypage" class="nav-link">마이페이지</a>
|
||||||
|
<a href="/cs" class="nav-link">고객센터</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Center: Search (Desktop) -->
|
||||||
|
<div class="search-bar">
|
||||||
|
<form action="/shop" method="GET">
|
||||||
|
<input type="text" name="search" class="search-input" placeholder="상품권/브랜드 검색 (예: 문상, 해피, 구글플레이)">
|
||||||
|
<button type="submit" class="search-icon" aria-label="검색">
|
||||||
|
<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right: Auth Buttons -->
|
||||||
|
<div class="auth-buttons flex items-center gap-2">
|
||||||
|
<a href="/login" class="btn btn-ghost">로그인</a>
|
||||||
|
<a href="/register" class="btn btn-primary" style="padding: 8px 20px;">회원가입</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mobile Menu Toggle (Hidden on Desktop) -->
|
||||||
|
<button class="mobile-menu-btn" aria-label="메뉴 열기" style="display: none;">
|
||||||
|
<svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16">
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Mobile Breakpoint Adjustments will be handled in CSS media queries -->
|
||||||
|
<style>
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
|
||||||
|
.desktop-nav,
|
||||||
|
.search-bar,
|
||||||
|
.auth-buttons {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-btn {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
45
resources/views/web/home.blade.php
Normal file
45
resources/views/web/home.blade.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
@extends('web.layouts.layout')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
{{-- Hero --}}
|
||||||
|
@include('web.main.hero-carousel')
|
||||||
|
|
||||||
|
{{-- Quick Categories --}}
|
||||||
|
@include('web.main.quick-categories')
|
||||||
|
|
||||||
|
{{-- Monthly Deals --}}
|
||||||
|
<section class="section" id="monthly-deals">
|
||||||
|
<div class="container">
|
||||||
|
@include('web.main.section-title', [
|
||||||
|
'title' => '이달의 할인',
|
||||||
|
'desc' => '이번 달 인기 할인 상품을 모아봤어요.'
|
||||||
|
])
|
||||||
|
|
||||||
|
@include('web.main.product-carousel')
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{-- Popular --}}
|
||||||
|
<section class="section" id="popular">
|
||||||
|
<div class="container">
|
||||||
|
@include('web.main.section-title', [
|
||||||
|
'title' => '인기상품',
|
||||||
|
'desc' => '최근 24시간 기준'
|
||||||
|
])
|
||||||
|
|
||||||
|
@include('web.main.product-row-scroll')
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{-- All Products --}}
|
||||||
|
<section class="section" id="all-products">
|
||||||
|
<div class="container">
|
||||||
|
@include('web.main.section-title', ['title' => '전체상품'])
|
||||||
|
|
||||||
|
@include('web.main.filter-tabs')
|
||||||
|
@include('web.main.product-grid')
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
@endsection
|
||||||
39
resources/views/web/layouts/layout.blade.php
Normal file
39
resources/views/web/layouts/layout.blade.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<title>Voucher Mall - 상품권 최저가 쇼핑</title>
|
||||||
|
|
||||||
|
{{-- SEO --}}
|
||||||
|
<meta name="description" content="상품권, 모바일 교환권, 구글플레이, 문화상품권 등 다양한 모바일 쿠폰 최저가 할인 쇼핑몰">
|
||||||
|
<link rel="canonical" href="{{ rtrim(config('app.url'), '/') }}/">
|
||||||
|
|
||||||
|
{{-- CSRF (추후 폼/로그인 대비) --}}
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
|
||||||
|
{{-- Pretendard Font --}}
|
||||||
|
<link rel="stylesheet" href="{{ asset('css/pretendard.css') }}">
|
||||||
|
<link rel="preload" href="{{ asset('assets/fonts/pretendard/PretendardVariable.woff2') }}" as="font" type="font/woff2" crossorigin>
|
||||||
|
|
||||||
|
{{-- ✅ WEB 전용 번들 로딩 --}}
|
||||||
|
@vite(['resources/css/web.css', 'resources/js/web.js'])
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
{{-- Header --}}
|
||||||
|
@include('web.company.header')
|
||||||
|
|
||||||
|
<main>
|
||||||
|
{{-- ✅ 페이지에서 @section('content')가 여기로 들어옴 --}}
|
||||||
|
@yield('content')
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{{-- Footer --}}
|
||||||
|
@include('web.company.footer')
|
||||||
|
|
||||||
|
{{-- 페이지별 스크립트 추가용 --}}
|
||||||
|
@stack('scripts')
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
7
resources/views/web/main/filter-tabs.blade.php
Normal file
7
resources/views/web/main/filter-tabs.blade.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<div class="filter-tabs" role="tablist">
|
||||||
|
<button class="tab-btn active" role="tab" aria-selected="true" data-filter="all">전체</button>
|
||||||
|
<button class="tab-btn" role="tab" aria-selected="false" data-filter="card">카드결제</button>
|
||||||
|
<button class="tab-btn" role="tab" aria-selected="false" data-filter="phone">핸드폰결제</button>
|
||||||
|
<button class="tab-btn" role="tab" aria-selected="false" data-filter="kbank">케이뱅크</button>
|
||||||
|
<button class="tab-btn" role="tab" aria-selected="false" data-filter="sale">할인판매</button>
|
||||||
|
</div>
|
||||||
52
resources/views/web/main/hero-carousel.blade.php
Normal file
52
resources/views/web/main/hero-carousel.blade.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<section class="hero-slider" aria-label="프로모션 배너">
|
||||||
|
<div class="hero-track">
|
||||||
|
<!-- Slide 1 -->
|
||||||
|
<div class="hero-slide" style="background: linear-gradient(135deg, #EFF6FF 0%, #FFFFFF 100%);">
|
||||||
|
<div class="container hero-content">
|
||||||
|
<span style="color: var(--color-accent-blue); font-weight: 700; margin-bottom: 8px; display: block;">특별
|
||||||
|
프로모션</span>
|
||||||
|
<h1 class="hero-title">구글플레이 기프트카드<br>최대 12% 즉시 할인</h1>
|
||||||
|
<p class="hero-desc">인기 게임 아이템부터 영화까지, 더 저렴하게 즐기세요.</p>
|
||||||
|
<a href="/shop?category=google" class="btn btn-primary">지금 구매하기</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Slide 2 -->
|
||||||
|
<div class="hero-slide" style="background: linear-gradient(135deg, #F0FDFA 0%, #FFFFFF 100%);">
|
||||||
|
<div class="container hero-content">
|
||||||
|
<span style="color: #059669; font-weight: 700; margin-bottom: 8px; display: block;">신규 입점</span>
|
||||||
|
<h1 class="hero-title">문화상품권 24시간<br>자동 발송 시스템 오픈</h1>
|
||||||
|
<p class="hero-desc">기다림 없이 결제 즉시 문자로 핀번호를 받아보세요.</p>
|
||||||
|
<a href="/shop?category=paper" class="btn btn-primary" style="background-color: #059669;">상품 보러가기</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Slide 3 -->
|
||||||
|
<div class="hero-slide" style="background: linear-gradient(135deg, #FFF7ED 0%, #FFFFFF 100%);">
|
||||||
|
<div class="container hero-content">
|
||||||
|
<span style="color: #EA580C; font-weight: 700; margin-bottom: 8px; display: block;">한정 수량</span>
|
||||||
|
<h1 class="hero-title">편의점 모바일 금액권<br>5만원권 10% 핫딜</h1>
|
||||||
|
<p class="hero-desc">CU, GS25, 세븐일레븐 전국 어디서나 사용 가능</p>
|
||||||
|
<a href="/shop?category=convenience" class="btn btn-primary" style="background-color: #EA580C;">구매하기</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="slider-arrow prev" aria-label="이전 슬라이드"
|
||||||
|
style="position: absolute; left: 24px; top: 50%; transform: translateY(-50%); width: 40px; height: 40px; border-radius: 50%; background: white; box-shadow: var(--shadow-md); display: flex; align-items: center; justify-content: center;">
|
||||||
|
<svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="slider-arrow next" aria-label="다음 슬라이드"
|
||||||
|
style="position: absolute; right: 24px; top: 50%; transform: translateY(-50%); width: 40px; height: 40px; border-radius: 50%; background: white; box-shadow: var(--shadow-md); display: flex; align-items: center; justify-content: center;">
|
||||||
|
<svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="dots-container">
|
||||||
|
<!-- Script will populate docs based on slide count -->
|
||||||
|
<div class="dot active"></div>
|
||||||
|
<div class="dot"></div>
|
||||||
|
<div class="dot"></div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
26
resources/views/web/main/product-carousel.blade.php
Normal file
26
resources/views/web/main/product-carousel.blade.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
@props(['products' => []])
|
||||||
|
|
||||||
|
<div class="snap-carousel" id="monthly-deals-carousel">
|
||||||
|
<!-- Mock Items if empty -->
|
||||||
|
@for($i = 1; $i <= 5; $i++)
|
||||||
|
<div class="snap-item">
|
||||||
|
<div class="product-card">
|
||||||
|
<div class="card-thumb">
|
||||||
|
<span style="color: #9CA3AF; font-size: 14px;">IMG</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h3 class="card-title">구글플레이 기프트카드 5만원권 특가 할인 [{{$i}}]</h3>
|
||||||
|
<div class="card-price-area">
|
||||||
|
<div class="price-row">
|
||||||
|
<span class="discount">-8%</span>
|
||||||
|
<span class="price">46,000</span>
|
||||||
|
</div>
|
||||||
|
<span class="original-price">50,000</span>
|
||||||
|
<br>
|
||||||
|
<span class="payment-badge">Card</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endfor
|
||||||
|
</div>
|
||||||
36
resources/views/web/main/product-grid.blade.php
Normal file
36
resources/views/web/main/product-grid.blade.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<div class="grid-cols-12 product-grid-container" id="all-products-grid">
|
||||||
|
<!-- Responsive sizing: Mobile 2col (spread), Tablet 4col (span 3), Desktop 4col (span 3) -->
|
||||||
|
<style>
|
||||||
|
.col-span-3 {
|
||||||
|
grid-column: span 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.col-span-3 {
|
||||||
|
grid-column: span 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2 columns on mobile */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
@for($i = 1; $i <= 12; $i++)
|
||||||
|
<div class="col-span-3 product-item" data-category="{{ $i % 3 == 0 ? 'card' : 'phone' }}">
|
||||||
|
<div class="product-card">
|
||||||
|
<div class="card-thumb">
|
||||||
|
<span style="color: #9CA3AF;">IMG</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h3 class="card-title">문화상품권 {{$i}}만원권 즉시발송</h3>
|
||||||
|
<div class="card-price-area">
|
||||||
|
<div class="price-row">
|
||||||
|
<span class="discount">-{{$i}}%</span>
|
||||||
|
<span class="price">{{50 - $i}},000</span>
|
||||||
|
</div>
|
||||||
|
<span class="payment-badge">{{ $i % 3 == 0 ? 'Card' : 'Phone' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endfor
|
||||||
|
</div>
|
||||||
20
resources/views/web/main/product-row-scroll.blade.php
Normal file
20
resources/views/web/main/product-row-scroll.blade.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<div style="overflow-x: auto; padding-bottom: 24px;">
|
||||||
|
<div style="display: flex; gap: 16px;">
|
||||||
|
@for($i = 1; $i <= 8; $i++)
|
||||||
|
<div style="flex: 0 0 200px;">
|
||||||
|
<div class="product-card">
|
||||||
|
<div class="card-thumb" style="aspect-ratio: 1/1;">
|
||||||
|
<span style="color: #9CA3AF;">Icon</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body" style="padding: 12px;">
|
||||||
|
<h3 class="card-title" style="font-size: 14px; height: 40px;">해피머니 상품권 {{$i}}만원권</h3>
|
||||||
|
<div class="card-price-area">
|
||||||
|
<span class="discount" style="font-size: 16px;">-5%</span>
|
||||||
|
<span class="price" style="font-size: 16px;">{{$i}}9,000</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endfor
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
23
resources/views/web/main/quick-categories.blade.php
Normal file
23
resources/views/web/main/quick-categories.blade.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<div class="container">
|
||||||
|
<div class="category-chips">
|
||||||
|
<a href="/shop?category=googleplay" class="chip">
|
||||||
|
<img src="https://via.placeholder.com/20/2563EB/FFFFFF?text=G" alt="" style="border-radius: 4px;"> Google
|
||||||
|
Play
|
||||||
|
</a>
|
||||||
|
<a href="/shop?category=paper" class="chip">
|
||||||
|
<img src="https://via.placeholder.com/20/purple/FFFFFF?text=C" alt="" style="border-radius: 4px;"> 문상/해피/도서
|
||||||
|
</a>
|
||||||
|
<a href="/shop?category=online" class="chip">
|
||||||
|
<img src="https://via.placeholder.com/20/orange/FFFFFF?text=O" alt="" style="border-radius: 4px;"> 온라인상품권
|
||||||
|
</a>
|
||||||
|
<a href="/shop?category=game" class="chip">
|
||||||
|
<img src="https://via.placeholder.com/20/green/FFFFFF?text=G" alt="" style="border-radius: 4px;"> 게임전용
|
||||||
|
</a>
|
||||||
|
<a href="/shop?category=convenience" class="chip">
|
||||||
|
<img src="https://via.placeholder.com/20/blue/FFFFFF?text=C" alt="" style="border-radius: 4px;"> 편의점
|
||||||
|
</a>
|
||||||
|
<a href="/shop?category=etc" class="chip">
|
||||||
|
<img src="https://via.placeholder.com/20/gray/FFFFFF?text=E" alt="" style="border-radius: 4px;"> 기타
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
8
resources/views/web/main/section-title.blade.php
Normal file
8
resources/views/web/main/section-title.blade.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<div class="section-header">
|
||||||
|
<div class="section-title">
|
||||||
|
<h2 class="text-h2">{{ $title }}</h2>
|
||||||
|
@if(!empty($desc))
|
||||||
|
<p class="text-body">{{ $desc }}</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
File diff suppressed because one or more lines are too long
@ -1,9 +1,23 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use App\Http\Controllers\Admin\Auth\AdminAuthController;
|
||||||
|
|
||||||
Route::middleware(['auth:admin'])->group(function () {
|
Route::middleware('guest:admin')->group(function () {
|
||||||
Route::get('/', function () {
|
Route::get('/login', [AdminAuthController::class, 'create'])
|
||||||
return 'admin ok';
|
->name('admin.login');
|
||||||
})->name('admin.home');
|
|
||||||
|
Route::post('/login', [AdminAuthController::class, 'store'])
|
||||||
|
->name('admin.login.store');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::middleware('auth:admin')->group(function () {
|
||||||
|
Route::get('/', function () {
|
||||||
|
return view('admin.home');
|
||||||
|
})->name('admin.home');
|
||||||
|
|
||||||
|
Route::post('/logout', [AdminAuthController::class, 'destroy'])
|
||||||
|
->name('admin.logout');
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::fallback(fn () => abort(404));
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
return view('welcome');
|
return view('web.home');
|
||||||
});
|
})->name('web.home');
|
||||||
|
|
||||||
|
Route::view('/', 'web.home')->name('web.home');
|
||||||
|
|
||||||
|
Route::fallback(fn () => abort(404));
|
||||||
|
|||||||
@ -5,7 +5,12 @@ import tailwindcss from '@tailwindcss/vite';
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
laravel({
|
laravel({
|
||||||
input: ['resources/css/app.css', 'resources/js/app.js'],
|
input: [
|
||||||
|
'resources/css/web.css',
|
||||||
|
'resources/js/web.js',
|
||||||
|
'resources/css/admin.css',
|
||||||
|
'resources/js/admin.js',
|
||||||
|
],
|
||||||
refresh: true,
|
refresh: true,
|
||||||
}),
|
}),
|
||||||
tailwindcss(),
|
tailwindcss(),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user