Skip to content

Commit 21f4382

Browse files
authored
Merge pull request #887 from w3bdesign/447-search
447 search
2 parents 2c37f68 + 88d12d8 commit 21f4382

File tree

7 files changed

+465
-136
lines changed

7 files changed

+465
-136
lines changed

app/Http/Controllers/Api/ProductController.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,26 @@
22

33
namespace App\Http\Controllers\Api;
44

5+
use Illuminate\Http\Request;
56
use App\Http\Controllers\Controller;
67
use App\Models\Product;
78

89
class ProductController extends Controller
910
{
10-
public function index()
11+
public function index(Request $request)
1112
{
12-
return Product::with(['categories' => function ($query) {
13+
$query = $request->get('q');
14+
15+
$products = Product::with(['categories' => function ($query) {
1316
$query->select('id', 'name');
14-
}])
15-
->get();
17+
}]);
18+
19+
if ($query) {
20+
$products->where('name', 'like', "%$query%")
21+
->orWhere('description', 'like', "%$query%");
22+
}
23+
24+
return $products->get();
1625
}
1726

1827
public function show($slug)

public/css/app.css

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,10 @@ video {
759759
margin-top: 2rem;
760760
}
761761

762+
.mb-4 {
763+
margin-bottom: 1rem;
764+
}
765+
762766
.block {
763767
display: block;
764768
}
@@ -855,6 +859,14 @@ video {
855859
height: 100vh;
856860
}
857861

862+
.h-\[70px\] {
863+
height: 70px;
864+
}
865+
866+
.max-h-full {
867+
max-height: 100%;
868+
}
869+
858870
.w-1\/2 {
859871
width: 50%;
860872
}
@@ -907,6 +919,62 @@ video {
907919
width: 100vw;
908920
}
909921

922+
.w-\[70px\] {
923+
width: 70px;
924+
}
925+
926+
.w-\[400px\] {
927+
width: 400px;
928+
}
929+
930+
.w-1\/3 {
931+
width: 33.333333%;
932+
}
933+
934+
.w-2\/3 {
935+
width: 66.666667%;
936+
}
937+
938+
.w-\[300px\] {
939+
width: 300px;
940+
}
941+
942+
.w-\[200px\] {
943+
width: 200px;
944+
}
945+
946+
.w-\[150px\] {
947+
width: 150px;
948+
}
949+
950+
.w-\[170px\] {
951+
width: 170px;
952+
}
953+
954+
.max-w-screen-xl {
955+
max-width: 1280px;
956+
}
957+
958+
.max-w-\[65px\] {
959+
max-width: 65px;
960+
}
961+
962+
.max-w-\[80px\] {
963+
max-width: 80px;
964+
}
965+
966+
.max-w-\[90px\] {
967+
max-width: 90px;
968+
}
969+
970+
.max-w-screen-sm {
971+
max-width: 640px;
972+
}
973+
974+
.max-w-screen-md {
975+
max-width: 768px;
976+
}
977+
910978
.flex-1 {
911979
flex: 1 1 0%;
912980
}
@@ -1095,6 +1163,14 @@ video {
10951163
overflow-x: auto;
10961164
}
10971165

1166+
.overflow-y-auto {
1167+
overflow-y: auto;
1168+
}
1169+
1170+
.overflow-x-hidden {
1171+
overflow-x: hidden;
1172+
}
1173+
10981174
.rounded {
10991175
border-radius: 0.25rem;
11001176
}
@@ -1129,6 +1205,22 @@ video {
11291205
border-width: 0px;
11301206
}
11311207

1208+
.border-2 {
1209+
border-width: 2px;
1210+
}
1211+
1212+
.border-t-2 {
1213+
border-top-width: 2px;
1214+
}
1215+
1216+
.border-t-4 {
1217+
border-top-width: 4px;
1218+
}
1219+
1220+
.border-b-2 {
1221+
border-bottom-width: 2px;
1222+
}
1223+
11321224
.border-blue-600 {
11331225
--tw-border-opacity: 1;
11341226
border-color: rgb(37 99 235 / var(--tw-border-opacity));
@@ -1154,6 +1246,16 @@ video {
11541246
border-color: rgb(209 213 219 / var(--tw-border-opacity));
11551247
}
11561248

1249+
.border-gray-500 {
1250+
--tw-border-opacity: 1;
1251+
border-color: rgb(107 114 128 / var(--tw-border-opacity));
1252+
}
1253+
1254+
.border-indigo-500 {
1255+
--tw-border-opacity: 1;
1256+
border-color: rgb(99 102 241 / var(--tw-border-opacity));
1257+
}
1258+
11571259
.border-opacity-50 {
11581260
--tw-border-opacity: 0.5;
11591261
}
@@ -1215,6 +1317,11 @@ video {
12151317
--tw-bg-opacity: 0.5;
12161318
}
12171319

1320+
.object-contain {
1321+
-o-object-fit: contain;
1322+
object-fit: contain;
1323+
}
1324+
12181325
.p-1 {
12191326
padding: 0.25rem;
12201327
}
@@ -1288,6 +1395,21 @@ video {
12881395
padding-bottom: 1rem;
12891396
}
12901397

1398+
.px-8 {
1399+
padding-left: 2rem;
1400+
padding-right: 2rem;
1401+
}
1402+
1403+
.py-16 {
1404+
padding-top: 4rem;
1405+
padding-bottom: 4rem;
1406+
}
1407+
1408+
.px-3 {
1409+
padding-left: 0.75rem;
1410+
padding-right: 0.75rem;
1411+
}
1412+
12911413
.pb-12 {
12921414
padding-bottom: 3rem;
12931415
}
@@ -1530,6 +1652,14 @@ video {
15301652
transition-duration: 700ms;
15311653
}
15321654

1655+
.duration-300 {
1656+
transition-duration: 300ms;
1657+
}
1658+
1659+
.duration-1000 {
1660+
transition-duration: 1000ms;
1661+
}
1662+
15331663
.ease-in-out {
15341664
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
15351665
}
@@ -1594,6 +1724,11 @@ video {
15941724
border-color: rgb(99 102 241 / var(--tw-border-opacity));
15951725
}
15961726

1727+
.focus\:border-blue-500:focus {
1728+
--tw-border-opacity: 1;
1729+
border-color: rgb(59 130 246 / var(--tw-border-opacity));
1730+
}
1731+
15971732
.focus\:outline-none:focus {
15981733
outline: 2px solid transparent;
15991734
outline-offset: 2px;

public/js/app.js

Lines changed: 243 additions & 93 deletions
Large diffs are not rendered by default.

resources/js/app.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Layout from "./layout/Layout.vue";
1010
import Cart from "./components/Header/Cart.vue";
1111
import Navbar from "./components/Header/Navbar.vue";
1212
import MobileMenu from "./components/Header/MobileMenu.vue";
13+
import Search from "./components/Header/Search.vue";
1314

1415
import ShowAllProducts from "./components/Products/ShowAllProducts.vue";
1516
import SingleProduct from "./components/Products/SingleProduct.vue";
@@ -44,6 +45,7 @@ app.component("carousel-component", Carousel);
4445
app.component("mobile-menu", MobileMenu);
4546

4647
app.component("nav-bar", Navbar);
48+
app.component("search", Search);
4749
app.component("footer-content", FooterContent);
4850
app.component("cart-component", Cart);
4951
app.component("layout-component", Layout);

resources/js/components/Header/Navbar.vue

Lines changed: 16 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,45 @@
11
<template>
2-
<header
3-
role="banner"
4-
class="container flex flex-col justify-center px-0 pt-6 mx-auto mb-6"
5-
>
2+
<header role="banner" class="container flex flex-col justify-center px-0 pt-6 mx-auto mb-6">
63
<div class="flex flex-wrap justify-between">
74
<div class="pr-2 my-2 overflow-hidden">
85
<div class="ml-4 lg:ml-0 hidden md:block">
96
<router-link to="/">
10-
<img
11-
alt="Logo"
12-
class="h-20 lg:h-24"
13-
aria-label="Nettbutikk logo"
14-
src="../../../img/svg/Logo.svg"
15-
/>
7+
<img alt="Logo" class="h-20 lg:h-24" aria-label="Nettbutikk logo" src="../../../img/svg/Logo.svg" />
168
</router-link>
179
</div>
1810
<router-link to="/">
19-
<img
20-
alt="Mobile logo"
21-
class="h-16 md:hidden block w-32"
22-
aria-label="Nettbutikk logo"
23-
src="../../../img/svg/MobileLogo.svg"
24-
/>
11+
<img alt="Mobile logo" class="h-16 md:hidden block w-32" aria-label="Nettbutikk logo"
12+
src="../../../img/svg/MobileLogo.svg" />
2513
</router-link>
2614
</div>
2715
<div class="lg:hidden block">
2816
<cart-component />
2917
</div>
3018
<mobile-menu />
3119
<div class="hidden lg:w-1/12 lg:block" />
32-
<div
33-
id="nav-content"
34-
class="hidden w-full mt-4 bg-black lg:w-8/12 lg:block lg:bg-white lg:mt-0 lg:text-right"
35-
aria-expanded="false"
36-
>
20+
<div id="nav-content" class="hidden w-full mt-4 bg-black lg:w-8/12 lg:block lg:bg-white lg:mt-0 lg:text-right"
21+
aria-expanded="false">
3722
<div class="px-6 lg:px-0 lg:pt-5 xl:pt-7">
3823
<nav id="block-main" role="navigation" aria-labelledby="block-main-menu">
3924
<ul class="items-center justify-end flex-1 pr-4 -mr-4 list-reset lg:flex">
40-
<li
41-
class="inline-block py-2 text-xl font-semibold no-underline lg:text-base pl-6"
42-
>
25+
<li class="inline-block py-2 text-xl font-semibold no-underline lg:text-base pl-6">
26+
<search />
27+
</li>
28+
<li class="inline-block py-2 text-xl font-semibold no-underline lg:text-base pl-6">
4329
<router-link tabindex="0" to="/">
44-
<span
45-
class="text-2xl text-white no-underline lg:text-black link-underline link-underline-blue"
46-
>
30+
<span class="text-2xl text-white no-underline lg:text-black link-underline link-underline-blue">
4731
Home
4832
</span>
4933
</router-link>
5034
</li>
51-
<li
52-
class="inline-block py-2 text-xl font-semibold no-underline lg:text-base pl-6"
53-
>
35+
<li class="inline-block py-2 text-xl font-semibold no-underline lg:text-base pl-6">
5436
<router-link tabindex="0" to="/products">
55-
<span
56-
class="text-2xl text-white no-underline lg:text-black link-underline link-underline-blue"
57-
>
37+
<span class="text-2xl text-white no-underline lg:text-black link-underline link-underline-blue">
5838
Products
5939
</span>
6040
</router-link>
6141
</li>
62-
<li
63-
class="inline-block py-2 text-xl font-semibold no-underline lg:text-base pl-6"
64-
>
42+
<li class="inline-block py-2 text-xl font-semibold no-underline lg:text-base pl-6">
6543
<cart-component />
6644
</li>
6745
</ul>
@@ -75,7 +53,8 @@
7553
<style scoped>
7654
.link-underline {
7755
border-bottom-width: 0;
78-
background-image: linear-gradient(transparent, transparent), linear-gradient(#fff, #fff);
56+
background-image: linear-gradient(transparent, transparent),
57+
linear-gradient(#fff, #fff);
7958
background-size: 0 3px;
8059
background-position: 0 100%;
8160
background-repeat: no-repeat;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<template>
2+
<input
3+
class="w-full px-3 py-2 my-2 border-2 border-gray-300 rounded-md text-sm focus:border-blue-500 focus:outline-none transition-all duration-300"
4+
type="text" v-model="searchTerm" placeholder="Search">
5+
6+
<div v-if="data && data.length > 0 && searchTerm.length > 0">
7+
<div
8+
class="flex justify-center absolute bg-white left-0 right-0 h-auto mx-auto py-16 px-8 shadow-md overflow-y-auto overflow-x-hidden scrolling-touch z-50 max-w-screen-md">
9+
<div class="w-full">
10+
<div v-for="product in data" :key="product.id" class="border-t-2 border-b-2 border-grey-500 py-4 w-full">
11+
<RouterLink :to="{
12+
name: 'single.product',
13+
params: { slug: product.slug },
14+
}">
15+
<div class="flex justify-end">
16+
<div class="h-[70px] w-[70px]">
17+
<img v-if="product.imageUrl"
18+
class="transform scale-70 max-w-[90px] max-h-full transition ease-in-out duration-200 transform-origin-center left-0 w-65 h-auto object-contain"
19+
:alt="product.name" :src="product.imageUrl" />
20+
</div>
21+
<div class="w-[170px]">
22+
<div class="product__name">
23+
<div class="product__title" :title="product.name">
24+
{{ product.name }}
25+
</div>
26+
</div>
27+
<div class="mt-4">
28+
<div class="product__price">
29+
{{ product.price }},-
30+
</div>
31+
</div>
32+
</div>
33+
</div>
34+
</RouterLink>
35+
</div>
36+
</div>
37+
</div>
38+
</div>
39+
</template>
40+
41+
<script setup>
42+
import { ref } from "vue";
43+
import useSWRV from "swrv";
44+
45+
const fetcher = (key) => fetch(key).then((res) => res.json());
46+
47+
const searchTerm = ref("");
48+
49+
const { data } = useSWRV(
50+
() => (searchTerm.value ? `/api/products?q=${searchTerm.value}` : null),
51+
fetcher
52+
);
53+
</script>

0 commit comments

Comments
 (0)