@kvass/widgets 1.0.17 → 1.1.0
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/dist/_plugin-vue_export-helper.js +1 -0
- package/dist/contact.js +8 -8
- package/dist/img-comparison-slider.js +2 -0
- package/dist/project-portal.js +6 -0
- package/index.html +16 -14
- package/package.json +9 -8
- package/src/contact/components/Form.ce.vue +6 -17
- package/src/img-comparison-slider/README.md +69 -0
- package/src/img-comparison-slider/components/ImgComparisonSlider.ce.vue +139 -0
- package/src/img-comparison-slider/main.js +7 -0
- package/src/project-portal/App.ce.vue +308 -0
- package/src/project-portal/api.js +48 -0
- package/src/project-portal/assets/logo.png +0 -0
- package/src/project-portal/assets/map-pin-solid.svg +1 -0
- package/src/project-portal/components/Card.ce.vue +110 -0
- package/src/project-portal/components/Category.ce.vue +87 -0
- package/src/project-portal/components/CategorySelector.ce.vue +43 -0
- package/src/project-portal/components/ProjectTypeSelector.ce.vue +70 -0
- package/src/project-portal/main.js +16 -0
- package/src/project-portal/styles/_variables.scss +19 -0
- package/src/project-portal/styles/components/_card.scss +178 -0
- package/vite.config.js +9 -7
|
@@ -246,19 +246,19 @@ onMounted(() => {
|
|
|
246
246
|
.kvass-contact {
|
|
247
247
|
// default variables
|
|
248
248
|
|
|
249
|
-
--kvass-contact-default-background: #
|
|
250
|
-
--kvass-contact-default-spacing:
|
|
249
|
+
--kvass-contact-default-background: #ffffff;
|
|
250
|
+
--kvass-contact-default-spacing: 2rem;
|
|
251
251
|
--kvass-contact-default-border-radius: 4px;
|
|
252
252
|
--kvass-contact-default-border-color: #eaeaea;
|
|
253
|
-
--kvass-contact-default-border-width:
|
|
253
|
+
--kvass-contact-default-border-width: 1px;
|
|
254
254
|
--kvass-contact-default-color: #222222;
|
|
255
|
-
--kvass-contact-default-color-inverted: #
|
|
255
|
+
--kvass-contact-default-color-inverted: #ffffff;
|
|
256
256
|
--kvass-contact-default-max-width: 720px;
|
|
257
257
|
--kvass-contact-default-primary: #1d56d8;
|
|
258
258
|
--kvass-contact-default-error: #d81d1d;
|
|
259
259
|
--kvass-contact-default-grid-columns: 1;
|
|
260
260
|
--kvass-contact-default-disabled: #eaeaea;
|
|
261
|
-
--kvass-contact-default-input-background: #
|
|
261
|
+
--kvass-contact-default-input-background: #ffffff;
|
|
262
262
|
--kvass-contact-default-outline-width: 2px;
|
|
263
263
|
--kvass-contact-default-outline-offset: 0px;
|
|
264
264
|
--kvass-contact-default-checkbox-size: 1em;
|
|
@@ -266,22 +266,11 @@ onMounted(() => {
|
|
|
266
266
|
--kvass-contact-default-checkbox-border-width: var(
|
|
267
267
|
--kvass-contact-default-border-width
|
|
268
268
|
);
|
|
269
|
+
|
|
269
270
|
--kvass-contact-default-checkbox-border-radius: var(
|
|
270
271
|
--kvass-contact-default-border-radius
|
|
271
272
|
);
|
|
272
273
|
|
|
273
|
-
--kvass-contact-border-radius: 20px;
|
|
274
|
-
|
|
275
|
-
--kvass-contact-border-width: 0;
|
|
276
|
-
--kvass-contact-checkbox-border-width: 0;
|
|
277
|
-
--kvass-contact-max-width: 440px;
|
|
278
|
-
--kvass-contact-label-transform: 10px;
|
|
279
|
-
--kvass-contact-form-spacing: 0rem;
|
|
280
|
-
--kvass-contact-spacing: 1.3rem;
|
|
281
|
-
--kvass-contact-field-input-tranform: 10px;
|
|
282
|
-
--kvass-contact-label-weight: bold;
|
|
283
|
-
--kvass-contact-success-label-font-size: 1.2em;
|
|
284
|
-
|
|
285
274
|
background-color: var(
|
|
286
275
|
--kvass-contact-background,
|
|
287
276
|
var(--kvass-contact-default-background)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# kvass-img-comparison-slider
|
|
2
|
+
|
|
3
|
+
A simple, embeddable Web Component to compare images.
|
|
4
|
+
|
|
5
|
+
`https://unpkg.com/@kvass/widgets@latest/dist/img-comparison-slider.js`
|
|
6
|
+
|
|
7
|
+
## Develop
|
|
8
|
+
|
|
9
|
+
To run in development mode, first install the neccessary packages.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
npm install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Then, run in development mode.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
npm run dev
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Open `localhost:3000` in the browser of your choice, and you will see the form widget.
|
|
22
|
+
|
|
23
|
+
## Build
|
|
24
|
+
|
|
25
|
+
To build the widget for production, run `build` instead of `dev`.
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
npm run build
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
To use the widget, use the `<kvass-img-comparison-slider />` element as shown here.
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<kvass-img-comparison-slider
|
|
35
|
+
first-image="https://example.com/first-image,First image"
|
|
36
|
+
second-image="https://example.com/second-image,Second image"
|
|
37
|
+
options="direction:vertical,keyboard:disabled"
|
|
38
|
+
></kvass-img-comparison-slider>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Props
|
|
42
|
+
|
|
43
|
+
The component has several props for easy configuration.
|
|
44
|
+
|
|
45
|
+
| Name | Type | Description | Enums |
|
|
46
|
+
| :---------- | :------ | :-------------------------------------------------------- | :---------------------- |
|
|
47
|
+
| **options** | String | key:value pairs separated by comma | The following options: |
|
|
48
|
+
| value | Number | Position of the divider in percents. | `0...100` |
|
|
49
|
+
| hover | Boolean | Automatically slide on mouse over. | `false`, `true` |
|
|
50
|
+
| direction | String | Set slider direction. | `horiontal`, `vertical` |
|
|
51
|
+
| nonce | | Define nonce which gets passed to inline style. | |
|
|
52
|
+
| keyboard | String | Enable/disable slider position control with the keyboard. | `enabled`, `disabled` |
|
|
53
|
+
| handle | Boolean | Enable/disable dragging by handle only. | `false`, `true` |
|
|
54
|
+
| | | | |
|
|
55
|
+
| first-image | String | Image url and text, separated by a comma | |
|
|
56
|
+
| second-mage | String | Image url and text, separated by a comma | |
|
|
57
|
+
| handle-svg | String | The svg on the slider handle | |
|
|
58
|
+
|
|
59
|
+
## Styling
|
|
60
|
+
|
|
61
|
+
The widget's styles are based on CSS custom properties, and can be overwritten.
|
|
62
|
+
These are the available CSS variables.
|
|
63
|
+
|
|
64
|
+
| Name | Description | Default |
|
|
65
|
+
| :------------------------ | :--------------------------------------------------------------------------------------- | :------ |
|
|
66
|
+
| `--divider-width` | Width of the vertical line separating both images | `1px` |
|
|
67
|
+
| `--divider-color` | Color of the vertical line separating the two images | `#fff` |
|
|
68
|
+
| `--divider-shadow` | Shadow cast by the vertical line separating the two images | `none` |
|
|
69
|
+
| `--handle-position-start` | Handle position on the divider axis. In case the handle must be displaced off the center | `50%` |
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ImgComparisonSlider } from '@img-comparison-slider/vue';
|
|
3
|
+
import { computed } from 'vue';
|
|
4
|
+
|
|
5
|
+
const defaultOptions = {
|
|
6
|
+
value: 50,
|
|
7
|
+
hover: false,
|
|
8
|
+
direction: 'horizontal',
|
|
9
|
+
keyboard: 'enabled',
|
|
10
|
+
handle: false,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function createImageObject(imageString) {
|
|
14
|
+
if (!imageString) return {}
|
|
15
|
+
|
|
16
|
+
const split = imageString.split(',')
|
|
17
|
+
return {
|
|
18
|
+
url: split[0],
|
|
19
|
+
description: split[1]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const props = defineProps({
|
|
24
|
+
firstImage: {
|
|
25
|
+
type: String,
|
|
26
|
+
default: 'https://assets.kvass.no/641c0b087c49867b0b1065ec,Første bilde'
|
|
27
|
+
},
|
|
28
|
+
secondImage: {
|
|
29
|
+
type: String,
|
|
30
|
+
default: 'https://assets.kvass.no/641c0a8c7c49867b0b106570,Andre bilde'
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
options: {
|
|
34
|
+
type: String,
|
|
35
|
+
default: '',
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
handleSvg: {
|
|
39
|
+
type: String,
|
|
40
|
+
default:
|
|
41
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-8 -3 16 6"><path stroke="#fff" d="M -3 -2 L -5 0 L -3 2 M -3 -2 L -3 2 M 3 -2 L 5 0 L 3 2 M 3 -2 L 3 2" stroke-width="1" fill="#fff" vector-effect="non-scaling-stroke"></path></svg>',
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// images
|
|
46
|
+
const firstImage = createImageObject(props.firstImage)
|
|
47
|
+
const firstImageCaption = computed(() => firstImage.description)
|
|
48
|
+
|
|
49
|
+
const secondImage = createImageObject(props.secondImage)
|
|
50
|
+
const secondImageCaption = computed(() => secondImage.description)
|
|
51
|
+
|
|
52
|
+
// options
|
|
53
|
+
const options = computed(() => {
|
|
54
|
+
const entries = props.options.split(',').map(entry => entry.split(':'))
|
|
55
|
+
return Object.fromEntries(entries)
|
|
56
|
+
})
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<template>
|
|
60
|
+
<ImgComparisonSlider
|
|
61
|
+
:style="`--first-image-caption: ${firstImageCaption}; --second-image-caption: ${secondImageCaption}`" tabindex="0"
|
|
62
|
+
class="img-comparison-slider" v-bind="{
|
|
63
|
+
...defaultOptions,
|
|
64
|
+
...options,
|
|
65
|
+
}">
|
|
66
|
+
<img slot="first" class="img-comparison-slider__image" :src="firstImage.url" />
|
|
67
|
+
<img slot="second" class="img-comparison-slider__image" :src="secondImage.url" />
|
|
68
|
+
|
|
69
|
+
<div slot="handle" class="handle">
|
|
70
|
+
<p class="handle__caption handle__caption--left">
|
|
71
|
+
{{ firstImage.description }}
|
|
72
|
+
</p>
|
|
73
|
+
<div class="handle__svg" v-html="handleSvg"></div>
|
|
74
|
+
<p class="handle__caption handle__caption--right">
|
|
75
|
+
{{ secondImage.description }}
|
|
76
|
+
</p>
|
|
77
|
+
</div>
|
|
78
|
+
</ImgComparisonSlider>
|
|
79
|
+
</template>
|
|
80
|
+
|
|
81
|
+
<style lang="scss">
|
|
82
|
+
.img-comparison-slider {
|
|
83
|
+
width: 100%;
|
|
84
|
+
height: 100%;
|
|
85
|
+
|
|
86
|
+
--divider-width: 4px;
|
|
87
|
+
--divider-color: black;
|
|
88
|
+
|
|
89
|
+
// aspect-ratio: var(--kvass-img-comparison-slider-aspect-ratio, $aspect-ratio);
|
|
90
|
+
// aspect-ratio: var(
|
|
91
|
+
// --kvass-img-comparison-slider-aspect-ratio,
|
|
92
|
+
// $aspect-ratio
|
|
93
|
+
// );
|
|
94
|
+
|
|
95
|
+
&__image {
|
|
96
|
+
width: 100%;
|
|
97
|
+
height: 100%;
|
|
98
|
+
object-fit: cover;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.handle {
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-direction: row;
|
|
104
|
+
|
|
105
|
+
justify-content: center;
|
|
106
|
+
align-items: center;
|
|
107
|
+
flex-wrap: nowrap;
|
|
108
|
+
gap: 1rem;
|
|
109
|
+
min-width: 800px;
|
|
110
|
+
|
|
111
|
+
font-size: 1rem;
|
|
112
|
+
|
|
113
|
+
@media (max-width: 600px) {
|
|
114
|
+
font-size: 0.75rem;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
&__caption {
|
|
118
|
+
color: white;
|
|
119
|
+
word-wrap: wrap;
|
|
120
|
+
width: 100%;
|
|
121
|
+
|
|
122
|
+
&--left {
|
|
123
|
+
text-align: right;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
&__svg {
|
|
128
|
+
padding: 0.3em;
|
|
129
|
+
background-color: black;
|
|
130
|
+
border-radius: 100%;
|
|
131
|
+
|
|
132
|
+
svg {
|
|
133
|
+
width: 2.5em;
|
|
134
|
+
height: 2.5em;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
</style>
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- <Loader :value="promise"> -->
|
|
3
|
+
<div class="project-selector" :class="`project-selector--theme-${theme}`">
|
|
4
|
+
<div
|
|
5
|
+
v-if="!disableNav || !navItems.length"
|
|
6
|
+
class="project-selector__navigation"
|
|
7
|
+
>
|
|
8
|
+
<CategorySelector
|
|
9
|
+
class="project-selector__navigation-category"
|
|
10
|
+
v-if="navItems.length"
|
|
11
|
+
:items="navItems"
|
|
12
|
+
:value="category"
|
|
13
|
+
@input="
|
|
14
|
+
($ev) => {
|
|
15
|
+
category = $ev
|
|
16
|
+
filterItems()
|
|
17
|
+
}
|
|
18
|
+
"
|
|
19
|
+
/>
|
|
20
|
+
|
|
21
|
+
<ProjectTypeSelector
|
|
22
|
+
v-if="projectTypes.length > 1"
|
|
23
|
+
class="project-selector__navigation-project-type"
|
|
24
|
+
:items="projectTypes"
|
|
25
|
+
:value="projectType"
|
|
26
|
+
@input="
|
|
27
|
+
($ev) => {
|
|
28
|
+
projectType = $ev.target.value
|
|
29
|
+
filterItems()
|
|
30
|
+
}
|
|
31
|
+
"
|
|
32
|
+
/>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<transition-group
|
|
36
|
+
v-if="items && items.length"
|
|
37
|
+
tag="div"
|
|
38
|
+
name="list"
|
|
39
|
+
appear
|
|
40
|
+
class="project-selector__card"
|
|
41
|
+
>
|
|
42
|
+
<Card
|
|
43
|
+
v-for="(item, index) in items"
|
|
44
|
+
:disable-label="disableNav"
|
|
45
|
+
:key="index"
|
|
46
|
+
:item="item"
|
|
47
|
+
theme="border"
|
|
48
|
+
/>
|
|
49
|
+
</transition-group>
|
|
50
|
+
|
|
51
|
+
<div class="project-selector__no-result" v-else>Ingen resultater</div>
|
|
52
|
+
</div>
|
|
53
|
+
<!-- </Loader> -->
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<script>
|
|
57
|
+
export default {
|
|
58
|
+
created() {
|
|
59
|
+
this.fetch()
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<script setup>
|
|
65
|
+
import { ref, computed } from 'vue'
|
|
66
|
+
|
|
67
|
+
import Card from './components/Card.ce.vue'
|
|
68
|
+
import CategorySelector from './components/CategorySelector.ce.vue'
|
|
69
|
+
import ProjectTypeSelector from './components/ProjectTypeSelector.ce.vue'
|
|
70
|
+
// import { LoaderComponent as Loader } from 'vue-elder-loader'
|
|
71
|
+
|
|
72
|
+
import { getProjects } from './api'
|
|
73
|
+
|
|
74
|
+
function getSortValue(type, value) {
|
|
75
|
+
switch (type) {
|
|
76
|
+
case 'status':
|
|
77
|
+
switch (value[type]) {
|
|
78
|
+
case 'sale':
|
|
79
|
+
return 2
|
|
80
|
+
case 'upcoming':
|
|
81
|
+
return 1
|
|
82
|
+
default:
|
|
83
|
+
return 0
|
|
84
|
+
}
|
|
85
|
+
case 'name':
|
|
86
|
+
return value[type]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const props = defineProps({
|
|
91
|
+
source: {
|
|
92
|
+
type: String,
|
|
93
|
+
default: 'https://feature.kvass.no',
|
|
94
|
+
},
|
|
95
|
+
startCategory: {
|
|
96
|
+
type: String,
|
|
97
|
+
default: 'all',
|
|
98
|
+
enums: ['all', 'sale', 'upcoming', 'development', 'sold'],
|
|
99
|
+
},
|
|
100
|
+
enabledCategories: {
|
|
101
|
+
type: String,
|
|
102
|
+
default: 'all,sale,upcoming,development,sold',
|
|
103
|
+
},
|
|
104
|
+
theme: {
|
|
105
|
+
type: String,
|
|
106
|
+
enum: ['default', 'tiles'],
|
|
107
|
+
default: 'default',
|
|
108
|
+
},
|
|
109
|
+
sortOn: {
|
|
110
|
+
type: String,
|
|
111
|
+
enum: ['status', 'name'],
|
|
112
|
+
default: 'status',
|
|
113
|
+
},
|
|
114
|
+
// triggerLabel: {
|
|
115
|
+
// type: String,
|
|
116
|
+
// default: 'Velg type',
|
|
117
|
+
// },
|
|
118
|
+
disableNav: {
|
|
119
|
+
type: Boolean,
|
|
120
|
+
default: false,
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
const category = ref('')
|
|
125
|
+
const projectType = ref('none')
|
|
126
|
+
const items = ref([])
|
|
127
|
+
var allItems = []
|
|
128
|
+
const promise = ref(null)
|
|
129
|
+
|
|
130
|
+
const navItems = computed(() => {
|
|
131
|
+
return [
|
|
132
|
+
...props.enabledCategories.split(',').filter((i) => {
|
|
133
|
+
if (i === 'all') return true
|
|
134
|
+
return allItems.find((k) => k.status.includes(i))
|
|
135
|
+
}),
|
|
136
|
+
]
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
const projectTypes = computed(() => {
|
|
140
|
+
let types = ['none'].concat(
|
|
141
|
+
allItems.map((i) => {
|
|
142
|
+
if (i.customFields && i.customFields['project-type'])
|
|
143
|
+
return i.customFields['project-type']
|
|
144
|
+
}),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return [...new Set(types || [])].filter(Boolean)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
function filterItems() {
|
|
151
|
+
items.value = allItems
|
|
152
|
+
.filter((i) => {
|
|
153
|
+
if (category.value === 'all') return true
|
|
154
|
+
return i.status.includes(category.value)
|
|
155
|
+
})
|
|
156
|
+
.filter((i) => {
|
|
157
|
+
if (!projectTypes.length || projectType.value === 'none') return true
|
|
158
|
+
if (!i.customFields || !i.customFields['project-type']) return
|
|
159
|
+
return i.customFields['project-type'].includes(projectType.value)
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function getFromSource() {
|
|
164
|
+
if (props.source) return getProjects(props.source)
|
|
165
|
+
return Promise.resolve()
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function getStatus(item) {
|
|
169
|
+
if (item.status) return item.status
|
|
170
|
+
let total = item.stats.total
|
|
171
|
+
if (item.isPublished && total && !item.stats.sale) return 'sold'
|
|
172
|
+
if (item.isPublished && total) return 'sale'
|
|
173
|
+
if (item.isPublished && !total) return 'upcoming'
|
|
174
|
+
if (!item.isPublished) return 'development'
|
|
175
|
+
return 'development'
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function fetch() {
|
|
179
|
+
promise.value = getFromSource()
|
|
180
|
+
.then(async (data) => {
|
|
181
|
+
let items = []
|
|
182
|
+
//read from global customItems
|
|
183
|
+
if (typeof customItems !== 'undefined') {
|
|
184
|
+
items =
|
|
185
|
+
typeof customItems === 'function' ? await customItems() : customItems
|
|
186
|
+
}
|
|
187
|
+
//remove kvass projects that is defined in customItems
|
|
188
|
+
let kvassProjects = data
|
|
189
|
+
? data.Projects.filter((item) => {
|
|
190
|
+
if (items.find((i) => (i.id ? i.id.includes(item.id) : undefined)))
|
|
191
|
+
return
|
|
192
|
+
return item
|
|
193
|
+
})
|
|
194
|
+
: []
|
|
195
|
+
|
|
196
|
+
allItems = [...kvassProjects, ...items]
|
|
197
|
+
|
|
198
|
+
return (allItems = allItems
|
|
199
|
+
.map((item) => {
|
|
200
|
+
item.status = getStatus(item)
|
|
201
|
+
return {
|
|
202
|
+
intro: item.customFields ? item.customFields['project-intro'] : '',
|
|
203
|
+
...item,
|
|
204
|
+
sortVale: getSortValue(props.sortOn, item),
|
|
205
|
+
url: item.url,
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
.sort((a, b) => {
|
|
209
|
+
switch (props.sortOn) {
|
|
210
|
+
case 'status':
|
|
211
|
+
if (a.sortVale < b.sortVale) return 1
|
|
212
|
+
if (a.sortVale > b.sortVale) return -1
|
|
213
|
+
}
|
|
214
|
+
})
|
|
215
|
+
.filter((i) => props.enabledCategories.split(',').includes(i.status)))
|
|
216
|
+
})
|
|
217
|
+
.then(() => {
|
|
218
|
+
category.value = props.startCategory
|
|
219
|
+
items.value = allItems
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
</script>
|
|
223
|
+
|
|
224
|
+
<style lang="scss">
|
|
225
|
+
@import './styles/_variables';
|
|
226
|
+
.project-selector {
|
|
227
|
+
$gap: 1.5rem;
|
|
228
|
+
&__navigation {
|
|
229
|
+
display: flex;
|
|
230
|
+
justify-content: var(--kvass-project-selector-nav-position, center);
|
|
231
|
+
padding: 0 2rem;
|
|
232
|
+
padding-bottom: 3rem;
|
|
233
|
+
gap: $gap;
|
|
234
|
+
@media (max-width: $kvass-project-selector-resposive) {
|
|
235
|
+
flex-direction: column-reverse;
|
|
236
|
+
justify-content: center;
|
|
237
|
+
gap: $gap - 1rem;
|
|
238
|
+
}
|
|
239
|
+
&-category {
|
|
240
|
+
display: flex;
|
|
241
|
+
justify-content: center;
|
|
242
|
+
gap: $gap;
|
|
243
|
+
@media (max-width: $kvass-project-selector-resposive) {
|
|
244
|
+
flex-direction: column;
|
|
245
|
+
gap: $gap - 1rem;
|
|
246
|
+
align-items: center;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
&__card {
|
|
251
|
+
position: relative;
|
|
252
|
+
display: grid;
|
|
253
|
+
grid-template-columns: repeat(
|
|
254
|
+
var(--kvass-project-selector-grid-columns, 4),
|
|
255
|
+
1fr
|
|
256
|
+
);
|
|
257
|
+
gap: var(--kvass-project-selector-grid-gap, 2rem);
|
|
258
|
+
@media (max-width: $kvass-project-selector-resposive) {
|
|
259
|
+
grid-template-columns: 1fr;
|
|
260
|
+
padding-top: 2rem;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
&__no-result {
|
|
264
|
+
font-size: 1.2em;
|
|
265
|
+
text-align: center;
|
|
266
|
+
display: flex;
|
|
267
|
+
justify-content: center;
|
|
268
|
+
align-items: center;
|
|
269
|
+
min-height: 200px;
|
|
270
|
+
margin: 2rem 0;
|
|
271
|
+
background-color: GetVariable('light-grey');
|
|
272
|
+
@media (max-width: $kvass-project-selector-resposive) {
|
|
273
|
+
min-height: 100px;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
.list {
|
|
277
|
+
&-leave-active {
|
|
278
|
+
position: absolute;
|
|
279
|
+
}
|
|
280
|
+
&-move,
|
|
281
|
+
&-enter-active,
|
|
282
|
+
&-leave-active {
|
|
283
|
+
transition: all 500ms ease;
|
|
284
|
+
}
|
|
285
|
+
&-enter {
|
|
286
|
+
transform: scale(0.95);
|
|
287
|
+
}
|
|
288
|
+
&-enter,
|
|
289
|
+
&-leave-to {
|
|
290
|
+
opacity: 0;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// tiles theme
|
|
295
|
+
.project-selector--theme-tiles {
|
|
296
|
+
.project-selector__card {
|
|
297
|
+
grid-template-columns: repeat(
|
|
298
|
+
var(--kvass-project-selector-grid-columns, 2),
|
|
299
|
+
1fr
|
|
300
|
+
);
|
|
301
|
+
gap: var(--kvass-project-selector-grid-gap, 0rem);
|
|
302
|
+
@media (max-width: $kvass-project-selector-resposive) {
|
|
303
|
+
grid-template-columns: 1fr;
|
|
304
|
+
padding-top: 2rem;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
</style>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
function getProjects(url) {
|
|
2
|
+
return fetch(`${url}/api/graphql`, {
|
|
3
|
+
method: 'POST',
|
|
4
|
+
headers: {
|
|
5
|
+
'Content-Type': 'application/json',
|
|
6
|
+
},
|
|
7
|
+
body: JSON.stringify({
|
|
8
|
+
query: `
|
|
9
|
+
query {
|
|
10
|
+
Projects {
|
|
11
|
+
id
|
|
12
|
+
name
|
|
13
|
+
url
|
|
14
|
+
isPublished
|
|
15
|
+
media {
|
|
16
|
+
cover {
|
|
17
|
+
url
|
|
18
|
+
type
|
|
19
|
+
}
|
|
20
|
+
gallery {
|
|
21
|
+
url
|
|
22
|
+
type
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
address {
|
|
26
|
+
street
|
|
27
|
+
city
|
|
28
|
+
county
|
|
29
|
+
postcode
|
|
30
|
+
location {
|
|
31
|
+
coordinates
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
stats {
|
|
35
|
+
total
|
|
36
|
+
sale
|
|
37
|
+
}
|
|
38
|
+
customFields(keys: ["project-intro", "project-type"])
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
`,
|
|
42
|
+
}),
|
|
43
|
+
})
|
|
44
|
+
.then((res) => res.json())
|
|
45
|
+
.then((res) => res.data)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { getProjects }
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="map-pin" class="svg-inline--fa fa-map-pin fa-w-9" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 288 512"><path fill="currentColor" d="M112 316.94v156.69l22.02 33.02c4.75 7.12 15.22 7.12 19.97 0L176 473.63V316.94c-10.39 1.92-21.06 3.06-32 3.06s-21.61-1.14-32-3.06zM144 0C64.47 0 0 64.47 0 144s64.47 144 144 144 144-64.47 144-144S223.53 0 144 0zm0 76c-37.5 0-68 30.5-68 68 0 6.62-5.38 12-12 12s-12-5.38-12-12c0-50.73 41.28-92 92-92 6.62 0 12 5.38 12 12s-5.38 12-12 12z"></path></svg>
|