<!doctype html>
<html>
<head>
<link rel="stylesheet" href="lib/style.css">
<script src="lib/script.js"></script>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { ref, computed, createApp } = Vue;
createApp({
setup() {
const products = ref([
{ id:'p1', name:'Runner Pro', price:12999, category:'Shoes', inStock:true, currency: "EUR" },
{ id:'p2', name:'Urban Tee', price: 2999, category:'T-Shirts', inStock:true, currency: "EUR" },
{ id:'p3', name:'Cap Classic',price: 1999, category:'Accessories', inStock:false, currency: "EUR" },
{ id:'p4', name:'Null Cat Tee',price:2599, category:null, inStock:true, currency: "EUR" },
]);
const q = ref('');
const sort = ref('asc');
const selected = ref(null);
const filtered = computed(() => {
// 1 implement filtering by category
// 2. implement sorting by price
return products.value
});
// 3. add price formating (respecting language and currency)
function format(price) {
return price;
}
return { q, sort, selected, filtered, format };
},
template: `
<div class="catalog">
<h1>Catalog</h1>
<div class="catalog__filters">
<input v-model="q" placeholder="Search by name" aria-label="Search"/>
<select v-model="selected" aria-label="Category">
<option :value="null">All</option>
<option>Shoes</option>
<option>T-Shirts</option>
<option>Accessories</option>
</select>
<select v-model="sort" aria-label="Sort by price">
<option value="asc">Price ↑</option>
<option value="desc">Price ↓</option>
</select>
</div>
<ul class="catalog__list">
<li v-for="p in filtered" :key="p.id" class="catalog-item">
<h3 class="catalog-item__title">{{ p.name }}</h3>
<div class="catalog-item__meta">
Category: {{ p.category ?? 'Unknown' }} •
<span :class="p.inStock ? 'catalog-item__stock--in' : 'catalog-item__stock--out'">
{{ p.inStock ? 'In stock' : 'Out of stock' }}
</span>
</div>
<strong>{{ format(p.price) }}</strong>
</li>
</ul>
</div>
`
}).mount('#app');
</script>
</body>
</html>
body {
font-family: system-ui;
background: #fafafa;
margin: 0;
padding: 0;
}
.catalog {
max-width: 900px;
margin: 16px auto;
padding: 0 12px;
}
.catalog__filters {
display: flex;
gap: 8px;
margin: 12px 0 20px 0;
}
.catalog__filters input,
.catalog__filters select {
padding: 6px 10px;
border: 1px solid #ccc;
border-radius: 6px;
font-size: 14px;
outline: none;
background: #ffffff;
}
.catalog__filters input:focus,
.catalog__filters select:focus {
border-color: #333;
}
.catalog__list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 12px;
list-style: none;
padding: 0;
margin: 0;
}
.catalog-item {
border: 1px solid #ddd;
border-radius: 12px;
padding: 12px;
background: #fff;
transition: box-shadow 0.2s ease;
}
.catalog-item:hover {
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
}
.catalog-item__title {
margin: 0 0 8px 0;
font-size: 16px;
}
.catalog-item__meta {
font-size: 12px;
color: #666;
margin-bottom: 6px;
}
.catalog-item__stock--in {
color: green;
}
.catalog-item__stock--out {
color: crimson;
}
// Add your code here