first commit

This commit is contained in:
2026-05-12 12:41:49 +07:00
commit 604fef891f
8368 changed files with 1285228 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
<template>
<aside class="card p-4">
<div class="mb-6">
<p class="text-xs font-bold uppercase tracking-wider text-slate-500">Menu User</p>
<h2 class="mt-1 text-lg font-extrabold">Dashboard</h2>
</div>
<nav class="grid gap-2">
<RouterLink class="side-link" to="/dashboard">
<LayoutDashboard size="18" />
Barang Saya
</RouterLink>
<RouterLink class="side-link" to="/jual">
<PlusCircle size="18" />
Jual Barang
</RouterLink>
<RouterLink class="side-link" to="/marketplace">
<Store size="18" />
Marketplace
</RouterLink>
<RouterLink class="side-link" to="/tersimpan">
<Heart size="18" />
Barang Tersimpan
</RouterLink>
<button class="side-link text-left" type="button" @click="logout">
<LogOut size="18" />
Logout
</button>
</nav>
</aside>
</template>
<script setup>
import { useRouter } from "vue-router"
import { Heart, LayoutDashboard, LogOut, PlusCircle, Store } from "lucide-vue-next"
import { clearAuth } from "../utils"
const router = useRouter()
function logout() {
clearAuth()
router.push("/login")
}
</script>
<style scoped>
.side-link {
@apply flex w-full items-center gap-3 rounded-xl px-3 py-3 text-sm font-semibold text-slate-700 transition hover:bg-slate-100;
}
.router-link-active {
@apply bg-brand-50 text-brand-700;
}
</style>
+29
View File
@@ -0,0 +1,29 @@
<template>
<footer class="border-t border-slate-200 bg-slate-950 text-white">
<div class="container-page py-10">
<div class="grid gap-8 md:grid-cols-3">
<div>
<h2 class="text-xl font-extrabold">SecondTech Market</h2>
<p class="mt-3 text-sm leading-6 text-slate-300">
Marketplace barang bekas teknologi untuk laptop, PC, monitor, keyboard, perangkat jaringan, dan server.
</p>
</div>
<div>
<h3 class="font-bold">Navigasi</h3>
<div class="mt-3 grid gap-2 text-sm text-slate-300">
<RouterLink to="/marketplace">Marketplace</RouterLink>
<RouterLink to="/jual">Jual Barang</RouterLink>
<RouterLink to="/dashboard">Dashboard</RouterLink>
</div>
</div>
<div>
<h3 class="font-bold">Catatan Project</h3>
<p class="mt-3 text-sm leading-6 text-slate-300">
Versi ini memakai backend Express, database MySQL, dan upload foto produk dari file perangkat.
</p>
</div>
</div>
<p class="mt-10 text-xs text-slate-400">© 2026 SecondTech Market. Dibuat untuk project web.</p>
</div>
</footer>
</template>
+90
View File
@@ -0,0 +1,90 @@
<template>
<header class="sticky top-0 z-50 border-b border-slate-200 bg-white/90 backdrop-blur">
<div class="container-page flex h-16 items-center justify-between">
<RouterLink to="/" class="flex items-center gap-2">
<div class="flex h-9 w-9 items-center justify-center rounded-xl bg-brand-600 text-white">
<Cpu size="20" />
</div>
<span class="text-lg font-extrabold tracking-tight">SecondTech</span>
</RouterLink>
<nav class="hidden items-center gap-6 md:flex">
<RouterLink class="nav-link" to="/">Home</RouterLink>
<RouterLink class="nav-link" to="/marketplace">Marketplace</RouterLink>
<RouterLink class="nav-link" to="/jual">Jual Barang</RouterLink>
<RouterLink class="nav-link" to="/dashboard">Dashboard</RouterLink>
<RouterLink class="nav-link" to="/tersimpan">Tersimpan</RouterLink>
</nav>
<div class="hidden items-center gap-3 md:flex">
<template v-if="currentUser">
<span class="text-sm font-bold text-slate-700">{{ currentUser.name }}</span>
<button class="btn-secondary !px-4 !py-2" @click="logout">Logout</button>
</template>
<template v-else>
<RouterLink to="/login" class="btn-secondary !px-4 !py-2">Login</RouterLink>
<RouterLink to="/register" class="btn-primary !px-4 !py-2">Register</RouterLink>
</template>
</div>
<button class="rounded-xl border border-slate-200 p-2 md:hidden" @click="open = !open">
<Menu />
</button>
</div>
<div v-if="open" class="border-t border-slate-200 bg-white md:hidden">
<div class="container-page grid gap-2 py-4">
<RouterLink class="mobile-link" to="/" @click="open=false">Home</RouterLink>
<RouterLink class="mobile-link" to="/marketplace" @click="open=false">Marketplace</RouterLink>
<RouterLink class="mobile-link" to="/jual" @click="open=false">Jual Barang</RouterLink>
<RouterLink class="mobile-link" to="/dashboard" @click="open=false">Dashboard</RouterLink>
<RouterLink class="mobile-link" to="/tersimpan" @click="open=false">Tersimpan</RouterLink>
<div v-if="currentUser" class="mt-2 grid gap-2">
<button class="btn-secondary !py-2 text-center" @click="logout">Logout</button>
</div>
<div v-else class="mt-2 grid grid-cols-2 gap-2">
<RouterLink to="/login" class="btn-secondary !py-2 text-center" @click="open=false">Login</RouterLink>
<RouterLink to="/register" class="btn-primary !py-2 text-center" @click="open=false">Register</RouterLink>
</div>
</div>
</div>
</header>
</template>
<script setup>
import { ref, watch } from "vue"
import { useRoute, useRouter } from "vue-router"
import { Cpu, Menu } from "lucide-vue-next"
import { clearAuth, getCurrentUser } from "../utils"
const open = ref(false)
const route = useRoute()
const router = useRouter()
const currentUser = ref(getCurrentUser())
watch(
() => route.fullPath,
() => {
currentUser.value = getCurrentUser()
}
)
function logout() {
clearAuth()
currentUser.value = null
open.value = false
router.push("/login")
}
</script>
<style scoped>
.nav-link {
@apply text-sm font-semibold text-slate-600 transition hover:text-brand-700;
}
.router-link-active {
@apply text-brand-700;
}
.mobile-link {
@apply rounded-xl px-3 py-2 text-sm font-semibold text-slate-700 hover:bg-slate-100;
}
</style>
+66
View File
@@ -0,0 +1,66 @@
<template>
<div class="card group overflow-hidden">
<div class="relative aspect-[4/3] overflow-hidden bg-slate-100">
<img :src="getProductImageUrl(product.image)" :alt="product.title" class="h-full w-full object-cover transition duration-500 group-hover:scale-105" />
<span class="absolute left-3 top-3 rounded-full bg-white/90 px-3 py-1 text-xs font-bold text-slate-700">
{{ product.category }}
</span>
<button
class="absolute right-3 top-3 rounded-full bg-white/90 p-2 text-slate-700 transition hover:bg-brand-600 hover:text-white"
@click.prevent="$emit('toggle-save', product.id)"
>
<Heart :fill="saved ? 'currentColor' : 'none'" size="18" />
</button>
</div>
<div class="p-4">
<div class="mb-2 flex items-center justify-between gap-3">
<span class="rounded-full bg-emerald-50 px-3 py-1 text-xs font-bold text-emerald-700">
{{ product.condition }}
</span>
<span class="text-xs font-semibold text-slate-500">{{ product.location }}</span>
</div>
<h3 class="line-clamp-2 min-h-[48px] text-base font-bold text-slate-900">
{{ product.title }}
</h3>
<p class="mt-2 text-lg font-extrabold text-brand-700">
{{ formatRupiah(product.price) }}
</p>
<div class="mt-4 flex gap-2">
<RouterLink :to="`/produk/${product.id}`" class="btn-secondary flex-1 !px-3 !py-2 text-center">
Detail
</RouterLink>
<a :href="waLink" target="_blank" class="btn-primary flex-1 !px-3 !py-2 text-center">
Massage
</a>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from "vue"
import { Heart } from "lucide-vue-next"
import { formatRupiah, getProductImageUrl } from "../utils"
const props = defineProps({
product: {
type: Object,
required: true
},
saved: {
type: Boolean,
default: false
}
})
defineEmits(["toggle-save"])
const waLink = computed(() => {
const text = encodeURIComponent(`Halo, saya tertarik dengan ${props.product.title} di SecondTech Market.`)
return `https://wa.me/${props.product.whatsapp}?text=${text}`
})
</script>