웹 메인페이지 레이아웃 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 () {
|
||||
Route::middleware('web')
|
||||
->domain('four.syye.net')
|
||||
->group(base_path('routes/site.php'));
|
||||
->group(base_path('routes/web.php'));
|
||||
|
||||
Route::middleware('web')
|
||||
->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
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\Admin\Auth\AdminAuthController;
|
||||
|
||||
Route::middleware(['auth:admin'])->group(function () {
|
||||
Route::get('/', function () {
|
||||
return 'admin ok';
|
||||
})->name('admin.home');
|
||||
Route::middleware('guest:admin')->group(function () {
|
||||
Route::get('/login', [AdminAuthController::class, 'create'])
|
||||
->name('admin.login');
|
||||
|
||||
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
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
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({
|
||||
plugins: [
|
||||
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,
|
||||
}),
|
||||
tailwindcss(),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user