@meeovi/layer-search 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +181 -0
- package/app/components/README.md +3 -0
- package/app/components/atoms/BaseButton.vue +36 -0
- package/app/components/atoms/BaseCard.vue +13 -0
- package/app/components/atoms/BaseCheckbox.vue +51 -0
- package/app/components/atoms/BaseLogo.vue +19 -0
- package/app/components/atoms/BaseText.vue +17 -0
- package/app/components/atoms/BaseTitle.vue +23 -0
- package/app/components/atoms/DiscordIcon.vue +14 -0
- package/app/components/atoms/GithubIcon.vue +14 -0
- package/app/components/atoms/HalfSolidStarIcon.vue +5 -0
- package/app/components/atoms/SelectArrow.vue +5 -0
- package/app/components/atoms/SolidStarIcon.vue +5 -0
- package/app/components/atoms/StarIcon.vue +5 -0
- package/app/components/atoms/TwitterIcon.vue +14 -0
- package/app/components/atoms/WebIcon.vue +12 -0
- package/app/components/atoms/XIcon.vue +5 -0
- package/app/components/features/aiSearch.vue +0 -0
- package/app/components/features/allSearch.vue +0 -0
- package/app/components/features/autocomplete.vue +0 -0
- package/app/components/features/imageSearch.vue +0 -0
- package/app/components/features/videoSearch.vue +0 -0
- package/app/components/filters/filters.vue +0 -0
- package/app/components/molecules/BaseSelect.vue +53 -0
- package/app/components/molecules/PageNumber.vue +54 -0
- package/app/components/molecules/RangeSlider.vue +37 -0
- package/app/components/molecules/SearchInput.vue +32 -0
- package/app/components/molecules/SocialLink.vue +42 -0
- package/app/components/molecules/StarRating.vue +48 -0
- package/app/components/organisms/LoadingIndicator.vue +12 -0
- package/app/components/organisms/MeiliSearchBar.vue +15 -0
- package/app/components/organisms/MeiliSearchFacetFilter.vue +116 -0
- package/app/components/organisms/MeiliSearchLoadingProvider.vue +29 -0
- package/app/components/organisms/MeiliSearchPagination.vue +40 -0
- package/app/components/organisms/MeiliSearchProvider.vue +51 -0
- package/app/components/organisms/MeiliSearchRangeFilter.vue +52 -0
- package/app/components/organisms/MeiliSearchRatingFilter.vue +47 -0
- package/app/components/organisms/MeiliSearchResults.vue +35 -0
- package/app/components/organisms/MeiliSearchSorting.vue +23 -0
- package/app/components/organisms/MeiliSearchStats.vue +13 -0
- package/app/components/organisms/ProductCard.vue +80 -0
- package/app/components/organisms/TheNavbar.vue +71 -0
- package/app/components/results/audioSearch.vue +7 -0
- package/app/components/results/booksSearch.vue +7 -0
- package/app/components/results/financeSearch.vue +93 -0
- package/app/components/results/imageSearch.vue +7 -0
- package/app/components/results/musicSearch.vue +93 -0
- package/app/components/results/newsSearch.vue +93 -0
- package/app/components/results/spaceSearch.vue +93 -0
- package/app/components/results/spacesSearch.vue +7 -0
- package/app/components/results/travelSearch.vue +93 -0
- package/app/components/results/videoSearch.vue +7 -0
- package/app/components/search.vue +87 -0
- package/app/components/templates/HomeTemplate.vue +44 -0
- package/app/components/widgets/ClearRefinements.vue +27 -0
- package/app/components/widgets/NoResults.vue +125 -0
- package/app/components/widgets/PriceSlider.css +58 -0
- package/app/composables/adapter/meilisearch.ts +58 -0
- package/app/composables/adapter/mock.ts +34 -0
- package/app/composables/adapter/opensearch.ts +66 -0
- package/app/composables/adapter/types.ts +14 -0
- package/app/composables/bridges/instantsearch.ts +20 -0
- package/app/composables/bridges/react.ts +40 -0
- package/app/composables/bridges/vue.ts +38 -0
- package/app/composables/cli.ts +85 -0
- package/app/composables/config/schema.ts +16 -0
- package/app/composables/config.ts +20 -0
- package/app/composables/core/Facets.ts +9 -0
- package/app/composables/core/Filters.ts +13 -0
- package/app/composables/core/Normalizers.ts +0 -0
- package/app/composables/core/Pipeline.ts +20 -0
- package/app/composables/core/QueryBuilder.ts +27 -0
- package/app/composables/core/SearchContext.ts +54 -0
- package/app/composables/core/SearchManager.ts +27 -0
- package/app/composables/events.ts +6 -0
- package/app/composables/index.ts +9 -0
- package/app/composables/module.ts +72 -0
- package/app/composables/types/api/global-search.ts +8 -0
- package/app/composables/types.d.ts +12 -0
- package/app/composables/utils/normalizers.ts +6 -0
- package/app/pages/results.vue +85 -0
- package/app/plugins/instantsearch.js +35 -0
- package/app/plugins/search.js +20 -0
- package/nuxt.config.ts +11 -0
- package/package.json +43 -0
- package/tsconfig.json +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
<!-- packages/search/README.md -->
|
|
2
|
+
# @meeovi/search
|
|
3
|
+
|
|
4
|
+
A modular, provider-agnostic search module for the Alternate Framework. It provides a unified, typed search API with pluggable adapters (Meilisearch, OpenSearch, mock adapters), a small CLI for indexing/warmup, and event hooks.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- Plug-and-play adapters (Meilisearch, OpenSearch, Mock)
|
|
9
|
+
- Fully typed integration with `@meeovi/core`
|
|
10
|
+
- Mock adapter for tests
|
|
11
|
+
- Small CLI for indexing and warmup
|
|
12
|
+
- Configuration validation and event hooks (`search:query`, `search:results`)
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
Using npm:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @meeovi/search
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Using pnpm:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pnpm add @meeovi/search
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Usage
|
|
29
|
+
|
|
30
|
+
Register the module with an Alternate app:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createAlternateApp } from '@meeovi/core'
|
|
34
|
+
import searchModule from '@meeovi/search'
|
|
35
|
+
|
|
36
|
+
const app = createAlternateApp({
|
|
37
|
+
config: {
|
|
38
|
+
search: {
|
|
39
|
+
defaultProvider: 'meilisearch',
|
|
40
|
+
providers: {
|
|
41
|
+
meilisearch: {
|
|
42
|
+
host: 'http://localhost:7700',
|
|
43
|
+
index: 'products',
|
|
44
|
+
apiKey: 'masterKey'
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
modules: [searchModule]
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
await app.start()
|
|
53
|
+
|
|
54
|
+
const search = app.context.getAdapter('search')
|
|
55
|
+
const results = await search.search({ term: 'shoes' })
|
|
56
|
+
console.log(results.items)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Adapters
|
|
60
|
+
|
|
61
|
+
Meilisearch adapter:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { createMeilisearchAdapter } from '@meeovi/search'
|
|
65
|
+
|
|
66
|
+
const adapter = createMeilisearchAdapter({
|
|
67
|
+
host: 'http://localhost:7700',
|
|
68
|
+
index: 'products',
|
|
69
|
+
apiKey: 'masterKey'
|
|
70
|
+
})
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
OpenSearch adapter:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { createOpenSearchAdapter } from '@meeovi/search'
|
|
77
|
+
|
|
78
|
+
const adapter = createOpenSearchAdapter({
|
|
79
|
+
endpoint: 'https://my-opensearch.com',
|
|
80
|
+
index: 'products',
|
|
81
|
+
apiKey: 'secret'
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Mock adapter (for testing):
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { createMockSearchAdapter } from '@meeovi/search'
|
|
89
|
+
|
|
90
|
+
const mock = createMockSearchAdapter([
|
|
91
|
+
{ id: '1', title: 'Red Shoes' },
|
|
92
|
+
{ id: '2', title: 'Blue Shirt' }
|
|
93
|
+
])
|
|
94
|
+
|
|
95
|
+
const results = await mock.search({ term: 'red' })
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Configuration
|
|
99
|
+
|
|
100
|
+
Example `search` config in your app:
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"search": {
|
|
105
|
+
"defaultProvider": "opensearch",
|
|
106
|
+
"providers": {
|
|
107
|
+
"opensearch": {
|
|
108
|
+
"endpoint": "https://my-opensearch.com",
|
|
109
|
+
"index": "products"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The module validates that `defaultProvider` and the referenced provider configuration exist, and that required fields for each adapter are present.
|
|
117
|
+
|
|
118
|
+
## Events
|
|
119
|
+
|
|
120
|
+
This module emits bus events that you can listen to:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
bus.on('search:query', ({ term }) => {
|
|
124
|
+
console.log('User searched for:', term)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
bus.on('search:results', ({ term, total }) => {
|
|
128
|
+
console.log(`Search for "${term}" returned ${total} results`)
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## CLI
|
|
133
|
+
|
|
134
|
+
Included CLI commands:
|
|
135
|
+
|
|
136
|
+
- Warmup: `meeovi-search warmup`
|
|
137
|
+
- Index a JSON file: `meeovi-search index ./products.json`
|
|
138
|
+
|
|
139
|
+
Environment variables supported (example for Meilisearch):
|
|
140
|
+
|
|
141
|
+
- `SEARCH_PROVIDER=meilisearch`
|
|
142
|
+
- `MEILI_HOST=http://localhost:7700`
|
|
143
|
+
- `MEILI_INDEX=products`
|
|
144
|
+
- `MEILI_KEY=masterKey`
|
|
145
|
+
|
|
146
|
+
## Testing
|
|
147
|
+
|
|
148
|
+
Use the mock adapter in tests to avoid external dependencies:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { createMockSearchAdapter } from '@meeovi/search'
|
|
152
|
+
|
|
153
|
+
const mock = createMockSearchAdapter([{ id: '1', title: 'Test Product' }])
|
|
154
|
+
const results = await mock.search({ term: 'test' })
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## File structure
|
|
158
|
+
|
|
159
|
+
Typical layout:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
@meeovi/search
|
|
163
|
+
├─ src/
|
|
164
|
+
│ ├─ index.ts
|
|
165
|
+
│ ├─ module.ts
|
|
166
|
+
│ ├─ adapter/
|
|
167
|
+
│ │ ├─ opensearch.ts
|
|
168
|
+
│ │ ├─ meilisearch.ts
|
|
169
|
+
│ │ ├─ mock.ts
|
|
170
|
+
│ │ └─ types.ts
|
|
171
|
+
│ ├─ config/schema.ts
|
|
172
|
+
│ ├─ events.ts
|
|
173
|
+
│ └─ utils/normalizers.ts
|
|
174
|
+
├─ cli.ts
|
|
175
|
+
├─ package.json
|
|
176
|
+
└─ README.md
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
interface Props {
|
|
3
|
+
color: 'dodger-blue' | 'hot-pink'
|
|
4
|
+
secondary?: boolean
|
|
5
|
+
size?: 'default' | 'small' | 'large'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
9
|
+
color: 'hot-pink',
|
|
10
|
+
secondary: false,
|
|
11
|
+
size: 'default'
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const { color, secondary, size } = toRefs(props)
|
|
15
|
+
|
|
16
|
+
const buttonColorClass = computed(() => `btn-${color.value}`)
|
|
17
|
+
const buttonSecondaryClass = computed(() => secondary.value ? 'btn-secondary' : '')
|
|
18
|
+
const buttonSizeClass = computed(() => {
|
|
19
|
+
if (size.value === 'default') { return '' }
|
|
20
|
+
return size.value === 'large'
|
|
21
|
+
? 'btn-lg'
|
|
22
|
+
: 'btn-sm'
|
|
23
|
+
})
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<template>
|
|
27
|
+
<button
|
|
28
|
+
class="btn"
|
|
29
|
+
:class="[buttonColorClass, buttonSecondaryClass, buttonSizeClass]"
|
|
30
|
+
type="button"
|
|
31
|
+
>
|
|
32
|
+
<slot name="default" />
|
|
33
|
+
</button>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<style src="~/assets/css/button.css"></style>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
const props = withDefaults(defineProps<{
|
|
3
|
+
value: boolean
|
|
4
|
+
name: string
|
|
5
|
+
label: string
|
|
6
|
+
disabled?: boolean
|
|
7
|
+
}>(), {
|
|
8
|
+
disabled: false
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
defineEmits<{
|
|
12
|
+
(e: 'update:value', checked: boolean): void
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const { name, label } = toRefs(props)
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div class="input-group" :class="{ disabled: disabled }">
|
|
20
|
+
<input
|
|
21
|
+
:id="name"
|
|
22
|
+
type="checkbox"
|
|
23
|
+
:name="name"
|
|
24
|
+
class="mr-2"
|
|
25
|
+
:checked="value"
|
|
26
|
+
:disabled="disabled"
|
|
27
|
+
@update="$emit('update:value', $event.target.checked)"
|
|
28
|
+
>
|
|
29
|
+
<label :for="name" class="body">
|
|
30
|
+
<slot name="default">
|
|
31
|
+
{{ label }}
|
|
32
|
+
</slot>
|
|
33
|
+
</label>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<style scoped>
|
|
38
|
+
.input-group {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: row;
|
|
41
|
+
align-items: center;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
input, label {
|
|
45
|
+
cursor: pointer;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
input:disabled, input:disabled + label {
|
|
49
|
+
cursor: not-allowed;
|
|
50
|
+
}
|
|
51
|
+
</style>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<img
|
|
3
|
+
src="../../assets/images/logo/light-background/default.svg"
|
|
4
|
+
alt="Meilisearch"
|
|
5
|
+
class="logo"
|
|
6
|
+
>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<style scoped>
|
|
10
|
+
.logo {
|
|
11
|
+
height: 1.5rem;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@media screen and (min-width: 1024px) {
|
|
15
|
+
.logo {
|
|
16
|
+
height: 2.25rem;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
const props = withDefaults(defineProps<{
|
|
3
|
+
size?: 'l' | 'm' | 's' | 'xs'
|
|
4
|
+
tag?: string
|
|
5
|
+
}>(), {
|
|
6
|
+
size: 'l',
|
|
7
|
+
tag: 'p'
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
const textSizeClass = computed(() => `body-${toRef(props, 'size').value}`)
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<component :is="tag" class="body" :class="textSizeClass">
|
|
15
|
+
<slot name="default" />
|
|
16
|
+
</component>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
const props = withDefaults(defineProps<{
|
|
3
|
+
size?: 's' | 'xs'
|
|
4
|
+
tag?: string
|
|
5
|
+
}>(), {
|
|
6
|
+
size: 's',
|
|
7
|
+
tag: 'div'
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
const size = toRef(props, 'size')
|
|
11
|
+
|
|
12
|
+
const textSizeClass = computed(() => {
|
|
13
|
+
return size.value === 's'
|
|
14
|
+
? 'title-caps'
|
|
15
|
+
: 'title-caps-xs'
|
|
16
|
+
})
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<component :is="tag" class="title" :class="[textSizeClass]">
|
|
21
|
+
<slot name="default" />
|
|
22
|
+
</component>
|
|
23
|
+
</template>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg
|
|
3
|
+
fill="currentColor"
|
|
4
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
5
|
+
viewBox="0 0 24 24"
|
|
6
|
+
class="h-6 w-6"
|
|
7
|
+
width="50px"
|
|
8
|
+
height="50px"
|
|
9
|
+
>
|
|
10
|
+
<path
|
|
11
|
+
d="M19.952,5.672c-1.904-1.531-4.916-1.79-5.044-1.801c-0.201-0.017-0.392,0.097-0.474,0.281 c-0.006,0.012-0.072,0.163-0.145,0.398c1.259,0.212,2.806,0.64,4.206,1.509c0.224,0.139,0.293,0.434,0.154,0.659 c-0.09,0.146-0.247,0.226-0.407,0.226c-0.086,0-0.173-0.023-0.252-0.072C15.584,5.38,12.578,5.305,12,5.305S8.415,5.38,6.011,6.872 c-0.225,0.14-0.519,0.07-0.659-0.154c-0.14-0.225-0.07-0.519,0.154-0.659c1.4-0.868,2.946-1.297,4.206-1.509 c-0.074-0.236-0.14-0.386-0.145-0.398C9.484,3.968,9.294,3.852,9.092,3.872c-0.127,0.01-3.139,0.269-5.069,1.822 C3.015,6.625,1,12.073,1,16.783c0,0.083,0.022,0.165,0.063,0.237c1.391,2.443,5.185,3.083,6.05,3.111c0.005,0,0.01,0,0.015,0 c0.153,0,0.297-0.073,0.387-0.197l0.875-1.202c-2.359-0.61-3.564-1.645-3.634-1.706c-0.198-0.175-0.217-0.477-0.042-0.675 c0.175-0.198,0.476-0.217,0.674-0.043c0.029,0.026,2.248,1.909,6.612,1.909c4.372,0,6.591-1.891,6.613-1.91 c0.198-0.172,0.5-0.154,0.674,0.045c0.174,0.198,0.155,0.499-0.042,0.673c-0.07,0.062-1.275,1.096-3.634,1.706l0.875,1.202 c0.09,0.124,0.234,0.197,0.387,0.197c0.005,0,0.01,0,0.015,0c0.865-0.027,4.659-0.667,6.05-3.111 C22.978,16.947,23,16.866,23,16.783C23,12.073,20.985,6.625,19.952,5.672z M8.891,14.87c-0.924,0-1.674-0.857-1.674-1.913 s0.749-1.913,1.674-1.913s1.674,0.857,1.674,1.913S9.816,14.87,8.891,14.87z M15.109,14.87c-0.924,0-1.674-0.857-1.674-1.913 s0.749-1.913,1.674-1.913c0.924,0,1.674,0.857,1.674,1.913S16.033,14.87,15.109,14.87z"
|
|
12
|
+
/>
|
|
13
|
+
</svg>
|
|
14
|
+
</template>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg
|
|
3
|
+
fill="currentColor"
|
|
4
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
5
|
+
viewBox="0 0 24 24"
|
|
6
|
+
class="h-6 w-6"
|
|
7
|
+
width="50px"
|
|
8
|
+
height="50px"
|
|
9
|
+
>
|
|
10
|
+
<path
|
|
11
|
+
d="M 12 2 C 6.476563 2 2 6.476563 2 12 C 2 17.523438 6.476563 22 12 22 C 17.523438 22 22 17.523438 22 12 C 22 6.476563 17.523438 2 12 2 Z M 12 4 C 16.410156 4 20 7.589844 20 12 C 20 12.46875 19.953125 12.929688 19.875 13.375 C 19.628906 13.320313 19.265625 13.253906 18.84375 13.25 C 18.53125 13.246094 18.140625 13.296875 17.8125 13.34375 C 17.925781 12.996094 18 12.613281 18 12.21875 C 18 11.257813 17.53125 10.363281 16.78125 9.625 C 16.988281 8.855469 17.191406 7.535156 16.65625 7 C 15.074219 7 14.199219 8.128906 14.15625 8.1875 C 13.667969 8.070313 13.164063 8 12.625 8 C 11.933594 8 11.273438 8.125 10.65625 8.3125 L 10.84375 8.15625 C 10.84375 8.15625 9.964844 6.9375 8.34375 6.9375 C 7.777344 7.507813 8.035156 8.953125 8.25 9.6875 C 7.484375 10.417969 7 11.28125 7 12.21875 C 7 12.546875 7.078125 12.859375 7.15625 13.15625 C 6.878906 13.125 5.878906 13.03125 5.46875 13.03125 C 5.105469 13.03125 4.542969 13.117188 4.09375 13.21875 C 4.03125 12.820313 4 12.414063 4 12 C 4 7.589844 7.589844 4 12 4 Z M 5.46875 13.28125 C 5.863281 13.28125 7.0625 13.421875 7.21875 13.4375 C 7.238281 13.492188 7.257813 13.542969 7.28125 13.59375 C 6.851563 13.554688 6.019531 13.496094 5.46875 13.5625 C 5.101563 13.605469 4.632813 13.738281 4.21875 13.84375 C 4.1875 13.71875 4.148438 13.597656 4.125 13.46875 C 4.5625 13.375 5.136719 13.28125 5.46875 13.28125 Z M 18.84375 13.5 C 19.242188 13.503906 19.605469 13.570313 19.84375 13.625 C 19.832031 13.691406 19.796875 13.746094 19.78125 13.8125 C 19.527344 13.753906 19.109375 13.667969 18.625 13.65625 C 18.390625 13.652344 18.015625 13.664063 17.6875 13.6875 C 17.703125 13.65625 17.707031 13.625 17.71875 13.59375 C 18.058594 13.546875 18.492188 13.496094 18.84375 13.5 Z M 6.09375 13.78125 C 6.65625 13.785156 7.183594 13.824219 7.40625 13.84375 C 7.929688 14.820313 8.988281 15.542969 10.625 15.84375 C 10.222656 16.066406 9.863281 16.378906 9.59375 16.75 C 9.359375 16.769531 9.113281 16.78125 8.875 16.78125 C 8.179688 16.78125 7.746094 16.160156 7.375 15.625 C 7 15.089844 6.539063 15.03125 6.28125 15 C 6.019531 14.96875 5.929688 15.117188 6.0625 15.21875 C 6.824219 15.804688 7.097656 16.5 7.40625 17.125 C 7.683594 17.6875 8.265625 18 8.90625 18 L 9.03125 18 C 9.011719 18.109375 9 18.210938 9 18.3125 L 9 19.40625 C 6.691406 18.472656 4.933594 16.5 4.28125 14.0625 C 4.691406 13.960938 5.152344 13.855469 5.5 13.8125 C 5.660156 13.792969 5.863281 13.777344 6.09375 13.78125 Z M 18.625 13.90625 C 19.074219 13.917969 19.472656 14.003906 19.71875 14.0625 C 19.167969 16.132813 17.808594 17.855469 16 18.90625 L 16 18.3125 C 16 17.460938 15.328125 16.367188 14.375 15.84375 C 15.957031 15.554688 16.988281 14.863281 17.53125 13.9375 C 17.910156 13.910156 18.355469 13.898438 18.625 13.90625 Z M 12.5 18 C 12.773438 18 13 18.226563 13 18.5 L 13 19.9375 C 12.671875 19.980469 12.339844 20 12 20 L 12 18.5 C 12 18.226563 12.226563 18 12.5 18 Z M 10.5 19 C 10.773438 19 11 19.226563 11 19.5 L 11 19.9375 C 10.664063 19.894531 10.324219 19.832031 10 19.75 L 10 19.5 C 10 19.226563 10.226563 19 10.5 19 Z M 14.5 19 C 14.742188 19 14.953125 19.175781 15 19.40625 C 14.675781 19.539063 14.34375 19.660156 14 19.75 L 14 19.5 C 14 19.226563 14.226563 19 14.5 19 Z"
|
|
12
|
+
/>
|
|
13
|
+
</svg>
|
|
14
|
+
</template>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.147 4.13091C12.711 3.12791 11.288 3.12791 10.853 4.13091L8.873 8.69691L3.919 9.16891C2.831 9.27191 2.391 10.6259 3.211 11.3499L6.941 14.6439L5.859 19.4999C5.621 20.5679 6.773 21.4039 7.715 20.8479L12 18.3199L16.285 20.8499C17.227 21.4059 18.378 20.5699 18.141 19.5019L17.059 14.6449L20.789 11.3509C21.609 10.6269 21.169 9.27291 20.08 9.16991L15.127 8.69791L13.147 4.13191V4.13091ZM12 15.9969L12.508 16.2969L15.813 18.2469L14.978 14.5019L14.85 13.9259L15.293 13.5359L18.169 10.9959L14.349 10.6319L13.761 10.5759L13.527 10.0339L12 6.51391V15.9969Z" fill="black" />
|
|
4
|
+
</svg>
|
|
5
|
+
</template>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path d="M3.75 7.23315L10.4506 13.9342L17.1517 7.23325" stroke="#492E6C" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
4
|
+
</svg>
|
|
5
|
+
</template>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.853 4.13091C11.288 3.12791 12.712 3.12791 13.147 4.13091L15.127 8.69691L20.081 9.16891C21.169 9.27191 21.609 10.6259 20.789 11.3499L17.059 14.6439L18.141 19.5009C18.379 20.5689 17.227 21.4049 16.285 20.8489L12 18.3199L7.715 20.8499C6.773 21.4059 5.621 20.5699 5.859 19.5019L6.941 14.6449L3.211 11.3509C2.391 10.6269 2.831 9.27291 3.92 9.16991L8.873 8.69791L10.853 4.13191V4.13091Z" fill="black" />
|
|
4
|
+
</svg>
|
|
5
|
+
</template>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.853 4.13091C11.288 3.12791 12.712 3.12791 13.147 4.13091L15.127 8.69691L20.081 9.16891C21.169 9.27191 21.609 10.6259 20.789 11.3499L17.059 14.6439L18.141 19.5009C18.379 20.5689 17.227 21.4049 16.285 20.8489L12 18.3199L7.715 20.8499C6.773 21.4059 5.621 20.5699 5.859 19.5019L6.941 14.6449L3.211 11.3509C2.391 10.6269 2.831 9.27291 3.92 9.16991L8.873 8.69791L10.853 4.13191V4.13091ZM12 6.51391L10.473 10.0339L10.239 10.5759L9.651 10.6319L5.831 10.9959L8.707 13.5359L9.15 13.9259L9.022 14.5019L8.187 18.2479L11.492 16.2969L12 15.9969L12.508 16.2969L15.813 18.2469L14.978 14.5019L14.85 13.9259L15.293 13.5359L18.169 10.9959L14.349 10.6319L13.761 10.5759L13.527 10.0339L12 6.51391Z" fill="black" />
|
|
4
|
+
</svg>
|
|
5
|
+
</template>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg
|
|
3
|
+
fill="currentColor"
|
|
4
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
5
|
+
viewBox="0 0 24 24"
|
|
6
|
+
class="h-6 w-6"
|
|
7
|
+
width="50px"
|
|
8
|
+
height="50px"
|
|
9
|
+
>
|
|
10
|
+
<path
|
|
11
|
+
d="M22,3.999c-0.78,0.463-2.345,1.094-3.265,1.276c-0.027,0.007-0.049,0.016-0.075,0.023c-0.813-0.802-1.927-1.299-3.16-1.299 c-2.485,0-4.5,2.015-4.5,4.5c0,0.131-0.011,0.372,0,0.5c-3.353,0-5.905-1.756-7.735-4c-0.199,0.5-0.286,1.29-0.286,2.032 c0,1.401,1.095,2.777,2.8,3.63c-0.314,0.081-0.66,0.139-1.02,0.139c-0.581,0-1.196-0.153-1.759-0.617c0,0.017,0,0.033,0,0.051 c0,1.958,2.078,3.291,3.926,3.662c-0.375,0.221-1.131,0.243-1.5,0.243c-0.26,0-1.18-0.119-1.426-0.165 c0.514,1.605,2.368,2.507,4.135,2.539c-1.382,1.084-2.341,1.486-5.171,1.486H2C3.788,19.145,6.065,20,8.347,20 C15.777,20,20,14.337,20,8.999c0-0.086-0.002-0.266-0.005-0.447C19.995,8.534,20,8.517,20,8.499c0-0.027-0.008-0.053-0.008-0.08 c-0.003-0.136-0.006-0.263-0.009-0.329c0.79-0.57,1.475-1.281,2.017-2.091c-0.725,0.322-1.503,0.538-2.32,0.636 C20.514,6.135,21.699,4.943,22,3.999z"
|
|
12
|
+
/>
|
|
13
|
+
</svg>
|
|
14
|
+
</template>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
fill="none"
|
|
5
|
+
viewBox="0 0 24 24"
|
|
6
|
+
stroke-width="1.5"
|
|
7
|
+
stroke="currentColor"
|
|
8
|
+
class="w-6 h-6"
|
|
9
|
+
>
|
|
10
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418" />
|
|
11
|
+
</svg>
|
|
12
|
+
</template>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.293 5.29308C5.48053 5.10561 5.73484 5.00029 6 5.00029C6.26516 5.00029 6.51947 5.10561 6.707 5.29308L12 10.5861L17.293 5.29308C17.3852 5.19757 17.4956 5.12139 17.6176 5.06898C17.7396 5.01657 17.8708 4.98898 18.0036 4.98783C18.1364 4.98668 18.2681 5.01198 18.391 5.06226C18.5138 5.11254 18.6255 5.18679 18.7194 5.28069C18.8133 5.37458 18.8875 5.48623 18.9378 5.60913C18.9881 5.73202 19.0134 5.8637 19.0123 5.99648C19.0111 6.12926 18.9835 6.26048 18.9311 6.38249C18.8787 6.50449 18.8025 6.61483 18.707 6.70708L13.414 12.0001L18.707 17.2931C18.8892 17.4817 18.99 17.7343 18.9877 17.9965C18.9854 18.2587 18.8802 18.5095 18.6948 18.6949C18.5094 18.8803 18.2586 18.9855 17.9964 18.9878C17.7342 18.99 17.4816 18.8892 17.293 18.7071L12 13.4141L6.707 18.7071C6.5184 18.8892 6.2658 18.99 6.0036 18.9878C5.7414 18.9855 5.49059 18.8803 5.30518 18.6949C5.11977 18.5095 5.0146 18.2587 5.01233 17.9965C5.01005 17.7343 5.11084 17.4817 5.293 17.2931L10.586 12.0001L5.293 6.70708C5.10553 6.51955 5.00021 6.26525 5.00021 6.00008C5.00021 5.73492 5.10553 5.48061 5.293 5.29308Z" fill="black" />
|
|
4
|
+
</svg>
|
|
5
|
+
</template>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
const props = defineProps<{
|
|
3
|
+
value?: string
|
|
4
|
+
options: Array<{
|
|
5
|
+
value: string
|
|
6
|
+
label: string
|
|
7
|
+
}>
|
|
8
|
+
}>()
|
|
9
|
+
|
|
10
|
+
defineEmits(['change'])
|
|
11
|
+
|
|
12
|
+
const options = toRef(props, 'options')
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<div class="select-group">
|
|
17
|
+
<select class="pr-5 input" @change="$emit('change', $event)">
|
|
18
|
+
<option
|
|
19
|
+
v-for="option in options"
|
|
20
|
+
:key="option.value"
|
|
21
|
+
:value="option.value"
|
|
22
|
+
:selected="option.value === value"
|
|
23
|
+
>
|
|
24
|
+
{{ option.label }}
|
|
25
|
+
</option>
|
|
26
|
+
</select>
|
|
27
|
+
<SelectArrow class="mr-4 select-arrow" />
|
|
28
|
+
</div>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<style src="~/assets/css/input.css"></style>
|
|
32
|
+
|
|
33
|
+
<style scoped>
|
|
34
|
+
.select-group {
|
|
35
|
+
position: relative;
|
|
36
|
+
display: inline-block;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.select-group select {
|
|
40
|
+
-moz-appearance:none; /* Firefox */
|
|
41
|
+
-webkit-appearance:none; /* Safari and Chrome */
|
|
42
|
+
appearance:none;
|
|
43
|
+
padding-right: calc(var(--size-4) + var(--size-2) + 20px);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.select-group .select-arrow {
|
|
47
|
+
display: inline;
|
|
48
|
+
position: absolute;
|
|
49
|
+
right: 0;
|
|
50
|
+
top: 50%;
|
|
51
|
+
transform: translate(0%, -50%);
|
|
52
|
+
}
|
|
53
|
+
</style>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
const props = withDefaults(defineProps<{
|
|
3
|
+
isCurrent: boolean
|
|
4
|
+
showSeparator?: boolean
|
|
5
|
+
separator?: 'before' | 'after'
|
|
6
|
+
hasGapSeparator?: boolean
|
|
7
|
+
}>(), {
|
|
8
|
+
showSeparator: true,
|
|
9
|
+
separator: 'after',
|
|
10
|
+
hasGapSeparator: false
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line func-call-spacing
|
|
14
|
+
defineEmits<{
|
|
15
|
+
(e: 'page-click'): void
|
|
16
|
+
}>()
|
|
17
|
+
|
|
18
|
+
const showSeparatorBefore = computed(() => props.showSeparator && props.separator === 'before')
|
|
19
|
+
const showSeparatorAfter = computed(() => props.showSeparator && props.separator === 'after')
|
|
20
|
+
|
|
21
|
+
const { isCurrent, hasGapSeparator } = toRefs(props)
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<BaseTitle tag="span">
|
|
26
|
+
<span
|
|
27
|
+
v-if="showSeparatorBefore"
|
|
28
|
+
class="text-ashes-900"
|
|
29
|
+
> •<span v-if="hasGapSeparator">••</span> </span>
|
|
30
|
+
<a
|
|
31
|
+
href="#"
|
|
32
|
+
class="link"
|
|
33
|
+
:class="{ 'active': isCurrent }"
|
|
34
|
+
@click.prevent="$emit('page-click')"
|
|
35
|
+
>
|
|
36
|
+
<slot name="default" />
|
|
37
|
+
</a>
|
|
38
|
+
<span
|
|
39
|
+
v-if="showSeparatorAfter"
|
|
40
|
+
class="text-ashes-900"
|
|
41
|
+
> •<span v-if="hasGapSeparator">••</span> </span>
|
|
42
|
+
</BaseTitle>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<style scoped>
|
|
46
|
+
.link {
|
|
47
|
+
text-decoration: none;
|
|
48
|
+
color: var(--ashes-900);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.link.active {
|
|
52
|
+
color: var(--dodger-blue-500);
|
|
53
|
+
}
|
|
54
|
+
</style>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import VueSlider from 'vue-slider-component/dist-css/vue-slider-component.umd.min.js'
|
|
3
|
+
import 'vue-slider-component/dist-css/vue-slider-component.css'
|
|
4
|
+
import 'vue-slider-component/theme/default.css'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
modelValue: [number, number]
|
|
8
|
+
min: number
|
|
9
|
+
max: number
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
defineEmits<{
|
|
13
|
+
(e: 'update:model-value', value: [number, number]): void
|
|
14
|
+
}>()
|
|
15
|
+
|
|
16
|
+
const { modelValue, min, max } = toRefs(props)
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<VueSlider
|
|
21
|
+
:model-value="modelValue"
|
|
22
|
+
:min="min"
|
|
23
|
+
:max="max"
|
|
24
|
+
:lazy="true"
|
|
25
|
+
tooltip="hover"
|
|
26
|
+
class="body"
|
|
27
|
+
:tooltip-style="{
|
|
28
|
+
background: 'var(--ashes-600)',
|
|
29
|
+
borderColor : 'var(--ashes-600)',
|
|
30
|
+
color: 'var(--valhalla-500)',
|
|
31
|
+
padding: 'var(--size-2)'
|
|
32
|
+
}"
|
|
33
|
+
:process-style="{ background: 'var(--dodger-blue-500)' }"
|
|
34
|
+
:tooltip-formatter="(value: number) => `$ ${value}`"
|
|
35
|
+
@change="$emit('update:model-value', ({ min: $event[0], max: $event[1] }))"
|
|
36
|
+
/>
|
|
37
|
+
</template>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
interface Props {
|
|
3
|
+
value: string
|
|
4
|
+
placeholder?: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
8
|
+
placeholder: 'Search...',
|
|
9
|
+
value: ''
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
defineEmits(['input', 'reset'])
|
|
13
|
+
|
|
14
|
+
const placeholder = toRef(props, 'placeholder')
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<form class="search-form">
|
|
19
|
+
<input
|
|
20
|
+
type="search"
|
|
21
|
+
:placeholder="placeholder"
|
|
22
|
+
:value="value"
|
|
23
|
+
class="input search-input"
|
|
24
|
+
@input="$emit('input', $event)"
|
|
25
|
+
>
|
|
26
|
+
<button type="reset" class="search-input-reset" @click="$emit('reset')">
|
|
27
|
+
<XIcon class="x-icon" />
|
|
28
|
+
</button>
|
|
29
|
+
</form>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<style src="~/assets/css/search.css"></style>
|