@ulu/frontend-vue 0.1.0-beta.2 → 0.1.0-beta.21
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 +113 -2
- package/dist/{breakpoints-ClT9bfZm.js → breakpoints-DOXmgVoG.js} +1 -1
- package/dist/frontend-vue.css +1 -1
- package/dist/frontend-vue.js +75 -73
- package/dist/index-BpmkfeZb.js +6671 -0
- package/lib/components/collapsible/UluAccordion.vue +1 -1
- package/lib/components/collapsible/UluModal.vue +4 -5
- package/lib/components/collapsible/UluOverflowPopover.vue +1 -1
- package/lib/components/elements/UluAlert.vue +1 -2
- package/lib/components/elements/UluBadge.vue +27 -28
- package/lib/components/elements/UluBadgeStack.vue +8 -13
- package/lib/components/elements/UluButton.vue +2 -2
- package/lib/components/elements/UluButtonVerbose.vue +119 -0
- package/lib/components/elements/UluCard.vue +1 -1
- package/lib/components/elements/UluDefinitionList.vue +14 -17
- package/lib/components/elements/UluExternalLink.vue +22 -29
- package/lib/components/elements/UluIcon.vue +22 -17
- package/lib/components/elements/UluList.vue +53 -55
- package/lib/components/elements/UluSpokeSpinner.vue +12 -18
- package/lib/components/elements/UluTag.vue +35 -35
- package/lib/components/forms/UluCheckboxMenu.vue +32 -31
- package/lib/components/forms/UluFileDisplay.vue +40 -31
- package/lib/components/forms/UluFormFile.vue +22 -24
- package/lib/components/forms/UluFormMessage.vue +7 -10
- package/lib/components/forms/UluFormSelect.vue +16 -16
- package/lib/components/forms/UluFormText.vue +15 -15
- package/lib/components/forms/UluSearchForm.vue +8 -10
- package/lib/components/index.js +1 -1
- package/lib/components/layout/UluAdaptiveLayout.vue +3 -5
- package/lib/components/layout/UluTitleRail.vue +9 -5
- package/lib/components/layout/UluWhenBreakpoint.vue +71 -77
- package/lib/components/navigation/UluBreadcrumb.vue +1 -2
- package/lib/components/navigation/UluMenu.vue +3 -3
- package/lib/components/navigation/UluPager.vue +102 -0
- package/lib/components/systems/facets/ExampleFacetsWithPagination.vue +119 -0
- package/lib/components/systems/facets/UluFacetsFilters.vue +73 -0
- package/lib/components/systems/facets/UluFacetsList.vue +13 -14
- package/lib/components/systems/facets/UluFacetsResults.vue +57 -0
- package/lib/components/systems/facets/UluFacetsSearch.vue +26 -49
- package/lib/components/systems/facets/UluFacetsSidebarLayout.vue +31 -0
- package/lib/components/systems/facets/UluFacetsSort.vue +45 -0
- package/lib/components/systems/facets/_facets.scss +2 -3
- package/lib/components/systems/facets/_mock-data.js +40 -0
- package/lib/components/systems/facets/useFacets.js +221 -0
- package/lib/components/systems/index.js +10 -2
- package/lib/components/systems/scroll-anchors/UluScrollAnchors.vue +2 -1
- package/lib/components/systems/skeleton/UluShowSkeleton.vue +9 -8
- package/lib/components/systems/skeleton/UluSkeletonContent.vue +39 -43
- package/lib/components/systems/skeleton/UluSkeletonMedia.vue +4 -6
- package/lib/components/systems/skeleton/UluSkeletonText.vue +27 -0
- package/lib/components/systems/slider/UluImageSlideShow.vue +1 -1
- package/lib/components/systems/slider/UluSlideShow.vue +8 -3
- package/lib/components/systems/table-sticky/UluTableSticky.vue +8 -8
- package/lib/components/systems/table-sticky/UluTableStickyTable.vue +3 -3
- package/lib/composables/index.js +3 -1
- package/lib/composables/useDocumentTitle.js +47 -0
- package/lib/composables/usePageTitle.js +37 -0
- package/lib/composables/usePagination.js +122 -0
- package/lib/composables/useRequiredInject.js +26 -0
- package/lib/index.js +1 -1
- package/lib/meta.js +14 -0
- package/lib/plugins/core/index.js +91 -0
- package/lib/plugins/index.js +1 -0
- package/lib/plugins/toast/UluToast.vue +2 -2
- package/lib/utils/index.js +2 -0
- package/lib/utils/{vue-router.js → router.js} +106 -11
- package/package.json +37 -14
- package/types/components/index.d.ts +2 -0
- package/types/components/index.d.ts.map +1 -0
- package/types/components/systems/facets/_mock-data.d.ts +18 -0
- package/types/components/systems/facets/_mock-data.d.ts.map +1 -0
- package/types/components/systems/facets/useFacets.d.ts +39 -0
- package/types/components/systems/facets/useFacets.d.ts.map +1 -0
- package/types/components/systems/index.d.ts +2 -0
- package/types/components/systems/index.d.ts.map +1 -0
- package/types/components/systems/scroll-anchors/symbols.d.ts +7 -0
- package/types/components/systems/scroll-anchors/symbols.d.ts.map +1 -0
- package/types/composables/index.d.ts +7 -0
- package/types/composables/index.d.ts.map +1 -0
- package/types/composables/useBreakpointManager.d.ts +8 -0
- package/types/composables/useBreakpointManager.d.ts.map +1 -0
- package/types/composables/useDocumentTitle.d.ts +18 -0
- package/types/composables/useDocumentTitle.d.ts.map +1 -0
- package/types/composables/useIcon.d.ts +6 -0
- package/types/composables/useIcon.d.ts.map +1 -0
- package/types/composables/useModifiers.d.ts +69 -0
- package/types/composables/useModifiers.d.ts.map +1 -0
- package/types/composables/usePageTitle.d.ts +19 -0
- package/types/composables/usePageTitle.d.ts.map +1 -0
- package/types/composables/usePagination.d.ts +25 -0
- package/types/composables/usePagination.d.ts.map +1 -0
- package/types/composables/useRequiredInject.d.ts +8 -0
- package/types/composables/useRequiredInject.d.ts.map +1 -0
- package/types/composables/useWindowResize.d.ts +6 -0
- package/types/composables/useWindowResize.d.ts.map +1 -0
- package/types/index.d.ts +5 -0
- package/types/index.d.ts.map +1 -0
- package/types/meta.d.ts +10 -0
- package/types/meta.d.ts.map +1 -0
- package/types/plugins/breakpoints/index.d.ts +2 -0
- package/types/plugins/breakpoints/index.d.ts.map +1 -0
- package/types/plugins/core/index.d.ts +3 -0
- package/types/plugins/core/index.d.ts.map +1 -0
- package/types/plugins/index.d.ts +6 -0
- package/types/plugins/index.d.ts.map +1 -0
- package/types/plugins/modals/api.d.ts +34 -0
- package/types/plugins/modals/api.d.ts.map +1 -0
- package/types/plugins/modals/index.d.ts +28 -0
- package/types/plugins/modals/index.d.ts.map +1 -0
- package/types/plugins/modals/useModals.d.ts +2 -0
- package/types/plugins/modals/useModals.d.ts.map +1 -0
- package/types/plugins/popovers/defaults.d.ts +14 -0
- package/types/plugins/popovers/defaults.d.ts.map +1 -0
- package/types/plugins/popovers/directive.d.ts +8 -0
- package/types/plugins/popovers/directive.d.ts.map +1 -0
- package/types/plugins/popovers/index.d.ts +7 -0
- package/types/plugins/popovers/index.d.ts.map +1 -0
- package/types/plugins/popovers/manager.d.ts +52 -0
- package/types/plugins/popovers/manager.d.ts.map +1 -0
- package/types/plugins/popovers/useFollow.d.ts +31 -0
- package/types/plugins/popovers/useFollow.d.ts.map +1 -0
- package/types/plugins/popovers/utils.d.ts +2 -0
- package/types/plugins/popovers/utils.d.ts.map +1 -0
- package/types/plugins/toast/defaults.d.ts +15 -0
- package/types/plugins/toast/defaults.d.ts.map +1 -0
- package/types/plugins/toast/index.d.ts +5 -0
- package/types/plugins/toast/index.d.ts.map +1 -0
- package/types/plugins/toast/store.d.ts +22 -0
- package/types/plugins/toast/store.d.ts.map +1 -0
- package/types/plugins/toast/useToast.d.ts +2 -0
- package/types/plugins/toast/useToast.d.ts.map +1 -0
- package/types/utils/dom.d.ts +8 -0
- package/types/utils/dom.d.ts.map +1 -0
- package/types/utils/index.d.ts +3 -0
- package/types/utils/index.d.ts.map +1 -0
- package/types/utils/placeholder.d.ts +8 -0
- package/types/utils/placeholder.d.ts.map +1 -0
- package/types/utils/router.d.ts +141 -0
- package/types/utils/router.d.ts.map +1 -0
- package/types/utils/vue-router.d.ts +122 -0
- package/types/utils/vue-router.d.ts.map +1 -0
- package/dist/frontend-vue.umd.cjs +0 -561
- package/dist/index-P5Rwl_Dl.js +0 -7263
- package/lib/components/forms/UluFormDropzone.vue +0 -62
- package/lib/components/systems/facets/UluFacets.vue +0 -380
- package/lib/components/systems/skeleton/UluSkeletonTextInline.vue +0 -9
- package/lib/settings.js +0 -119
- package/lib/utils/placeholder.js +0 -6
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<slot :item="item" :index="index">
|
|
27
27
|
<UluIcon
|
|
28
28
|
v-if="item.icon"
|
|
29
|
-
:
|
|
29
|
+
:icon="item.icon"
|
|
30
30
|
:class="[classes.linkIcon, item?.classes?.linkIcon]"
|
|
31
31
|
/>
|
|
32
32
|
<span :class="[classes.linkText, item?.classes?.linkText]">{{ item.title }}</span>
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
/**
|
|
61
61
|
* Fired anytime a item is clicked
|
|
62
62
|
*/
|
|
63
|
-
"
|
|
63
|
+
"item-click"
|
|
64
64
|
],
|
|
65
65
|
props: {
|
|
66
66
|
/**
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
if (item.click) {
|
|
99
99
|
item.click(event);
|
|
100
100
|
}
|
|
101
|
-
this.$emit("
|
|
101
|
+
this.$emit("item-click", { item, event });
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<nav v-if="items" class="pager" role="navigation" :aria-labelledby="headingId">
|
|
3
|
+
<component :is="titleElement" :id="headingId" class="hidden-visually">Pagination</component>
|
|
4
|
+
<ul class="pager__items js-pager__items">
|
|
5
|
+
<!-- First page link -->
|
|
6
|
+
<li v-if="items.first" class="pager__item pager__item--first">
|
|
7
|
+
<router-link :to="items.first.href" title="Go to first page" v-bind="items.first.attributes">
|
|
8
|
+
<span class="hidden-visually">First page</span>
|
|
9
|
+
<UluIcon icon="fas fa-angle-double-left" aria-hidden="true" />
|
|
10
|
+
</router-link>
|
|
11
|
+
</li>
|
|
12
|
+
|
|
13
|
+
<!-- Previous page link -->
|
|
14
|
+
<li v-if="items.previous" class="pager__item pager__item--previous">
|
|
15
|
+
<router-link :to="items.previous.href" title="Go to previous page" rel="prev" v-bind="items.previous.attributes">
|
|
16
|
+
<span class="hidden-visually">Previous page</span>
|
|
17
|
+
<UluIcon icon="fas fa-angle-left" aria-hidden="true" />
|
|
18
|
+
</router-link>
|
|
19
|
+
</li>
|
|
20
|
+
|
|
21
|
+
<!-- Ellipsis for previous pages -->
|
|
22
|
+
<li v-if="ellipses.previous" class="pager__item pager__item--ellipsis" role="presentation">…</li>
|
|
23
|
+
|
|
24
|
+
<!-- Page number links -->
|
|
25
|
+
<li v-for="(item, key) in items.pages" :key="key" :class="['pager__item', { 'is-active': current == key }]">
|
|
26
|
+
<router-link :to="item.href" :title="getPageTitle(key)" v-bind="item.attributes">
|
|
27
|
+
<span class="hidden-visually">
|
|
28
|
+
{{ current == key ? 'Current page' : 'Page' }}
|
|
29
|
+
</span>
|
|
30
|
+
{{ key }}
|
|
31
|
+
</router-link>
|
|
32
|
+
</li>
|
|
33
|
+
|
|
34
|
+
<!-- Ellipsis for next pages -->
|
|
35
|
+
<li v-if="ellipses.next" class="pager__item pager__item--ellipsis" role="presentation">…</li>
|
|
36
|
+
|
|
37
|
+
<!-- Next page link -->
|
|
38
|
+
<li v-if="items.next" class="pager__item pager__item--next">
|
|
39
|
+
<router-link :to="items.next.href" title="Go to next page" rel="next" v-bind="items.next.attributes">
|
|
40
|
+
<span class="hidden-visually">Next page</span>
|
|
41
|
+
<UluIcon icon="fas fa-angle-right" aria-hidden="true" />
|
|
42
|
+
</router-link>
|
|
43
|
+
</li>
|
|
44
|
+
|
|
45
|
+
<!-- Last page link -->
|
|
46
|
+
<li v-if="items.last" class="pager__item pager__item--last">
|
|
47
|
+
<router-link :to="items.last.href" title="Go to last page" v-bind="items.last.attributes">
|
|
48
|
+
<span class="hidden-visually">Last page</span>
|
|
49
|
+
<UluIcon icon="fas fa-angle-double-right" aria-hidden="true" />
|
|
50
|
+
</router-link>
|
|
51
|
+
</li>
|
|
52
|
+
</ul>
|
|
53
|
+
</nav>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<script setup>
|
|
57
|
+
import UluIcon from '../elements/UluIcon.vue';
|
|
58
|
+
|
|
59
|
+
let pagerCounter = 0;
|
|
60
|
+
|
|
61
|
+
const props = defineProps({
|
|
62
|
+
/**
|
|
63
|
+
* The HTML element to use for the visually hidden title.
|
|
64
|
+
*/
|
|
65
|
+
titleElement: {
|
|
66
|
+
type: String,
|
|
67
|
+
default: 'h4'
|
|
68
|
+
},
|
|
69
|
+
/**
|
|
70
|
+
* List of pager items.
|
|
71
|
+
*/
|
|
72
|
+
items: {
|
|
73
|
+
type: Object,
|
|
74
|
+
default: () => ({})
|
|
75
|
+
},
|
|
76
|
+
/**
|
|
77
|
+
* The page number of the current page.
|
|
78
|
+
*/
|
|
79
|
+
current: {
|
|
80
|
+
type: Number,
|
|
81
|
+
default: 1
|
|
82
|
+
},
|
|
83
|
+
/**
|
|
84
|
+
* Ellipses configuration.
|
|
85
|
+
*/
|
|
86
|
+
ellipses: {
|
|
87
|
+
type: Object,
|
|
88
|
+
default: () => ({})
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const headingId = `ulu-pager-${ pagerCounter++ }`;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Generates the title for a page link.
|
|
96
|
+
* @param {string|number} key - The page number.
|
|
97
|
+
* @returns {string} The title for the page link.
|
|
98
|
+
*/
|
|
99
|
+
function getPageTitle(key) {
|
|
100
|
+
return props.current == key ? 'Current page' : `Go to page ${key}`;
|
|
101
|
+
}
|
|
102
|
+
</script>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="BibliographyList">
|
|
3
|
+
<LayoutListPage title="Bibliography" icon="type:bibliography">
|
|
4
|
+
<template #intro>
|
|
5
|
+
<AppContent uid="bibliographyIntroduction" />
|
|
6
|
+
</template>
|
|
7
|
+
<template #default>
|
|
8
|
+
<UluFacetsSidebarLayout>
|
|
9
|
+
<template #sidebar>
|
|
10
|
+
<UluFacetsSearch v-model="searchValue" />
|
|
11
|
+
<UluFacetsSort v-model="selectedSort" :sort-types="sortTypes" />
|
|
12
|
+
<UluFacetsFilters :facets="facets" @facet-change="handleFacetChange" />
|
|
13
|
+
</template>
|
|
14
|
+
<template #main>
|
|
15
|
+
<UluFacetsResults :items="paginatedItems">
|
|
16
|
+
<template #item="{ item }">
|
|
17
|
+
<div class="source-item">
|
|
18
|
+
<h3>{{ item.title || "NO TITLE" }}</h3>
|
|
19
|
+
<div>
|
|
20
|
+
<PortableText v-if="item.citation" :value="item.citation" />
|
|
21
|
+
</div>
|
|
22
|
+
<small v-if="item.publicationDate">Published on: {{ item.publicationDate }}</small>
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
|
25
|
+
</UluFacetsResults>
|
|
26
|
+
<UluPager
|
|
27
|
+
v-if="totalPages > 1"
|
|
28
|
+
:items="pagerItems"
|
|
29
|
+
:current="currentPage"
|
|
30
|
+
:ellipses="pagerEllipses"
|
|
31
|
+
class="mt-4"
|
|
32
|
+
/>
|
|
33
|
+
</template>
|
|
34
|
+
</UluFacetsSidebarLayout>
|
|
35
|
+
</template>
|
|
36
|
+
</LayoutListPage>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
40
|
+
<script setup>
|
|
41
|
+
import { ref } from "vue";
|
|
42
|
+
import { PortableText } from "@portabletext/vue";
|
|
43
|
+
import sources from "@/api/virtual/sources.js?virtual-module";
|
|
44
|
+
import {
|
|
45
|
+
useFacets,
|
|
46
|
+
usePagination,
|
|
47
|
+
UluFacetsSidebarLayout,
|
|
48
|
+
UluFacetsFilters,
|
|
49
|
+
UluFacetsSort,
|
|
50
|
+
UluFacetsSearch,
|
|
51
|
+
UluFacetsResults
|
|
52
|
+
} from "@ulu/frontend-vue";
|
|
53
|
+
|
|
54
|
+
const sorterDateLatest = (a, b) => new Date(b.publicationDate) - new Date(a.publicationDate);
|
|
55
|
+
|
|
56
|
+
const config = {
|
|
57
|
+
facetFields: [
|
|
58
|
+
{ name: "Chapters", uid: "chapters", open: false, getValue: item => item.chapters?.map(c => c.uuid) },
|
|
59
|
+
{ name: "Types", uid: "types", open: true },
|
|
60
|
+
{ name: "Topics", uid: "topics", open: true },
|
|
61
|
+
{ name: "Citation Type", uid: "citationType", open: true },
|
|
62
|
+
{ name: "Source Type", uid: "sourceType", open: true },
|
|
63
|
+
{ name: "Authors", uid: "authors", open: false },
|
|
64
|
+
{ name: "Source Name", uid: "sourceName", open: false }
|
|
65
|
+
],
|
|
66
|
+
extraSortTypes: {
|
|
67
|
+
newest: {
|
|
68
|
+
text: "Date (Newest)",
|
|
69
|
+
sort: items => [...items].sort(sorterDateLatest)
|
|
70
|
+
},
|
|
71
|
+
oldest: {
|
|
72
|
+
text: "Date (Oldest)",
|
|
73
|
+
sort: items => [...items].sort(sorterDateLatest).reverse()
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
initialSortType: "az",
|
|
77
|
+
// Remove quotes and stuff from beginning when sorting
|
|
78
|
+
getSortValue: item => item.title ? item.title.replace(/^[^A-Za-z0-9]+/, "") : "",
|
|
79
|
+
searchOptions: {
|
|
80
|
+
keys: ["title", "authors", "sourceName", "topics", "types", "citation"]
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const itemsPerPage = 20;
|
|
85
|
+
|
|
86
|
+
const {
|
|
87
|
+
facets,
|
|
88
|
+
searchValue,
|
|
89
|
+
selectedSort,
|
|
90
|
+
sortTypes,
|
|
91
|
+
displayItems,
|
|
92
|
+
handleFacetChange,
|
|
93
|
+
} = useFacets(ref(sources), config);
|
|
94
|
+
|
|
95
|
+
const {
|
|
96
|
+
currentPage,
|
|
97
|
+
totalPages,
|
|
98
|
+
paginatedItems,
|
|
99
|
+
pagerItems,
|
|
100
|
+
pagerEllipses
|
|
101
|
+
} = usePagination(displayItems, itemsPerPage);
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
<style lang="scss">
|
|
105
|
+
// Add some basic styling for the item display
|
|
106
|
+
.source-item {
|
|
107
|
+
padding: 1rem;
|
|
108
|
+
border-bottom: 1px solid #eee;
|
|
109
|
+
|
|
110
|
+
h3 {
|
|
111
|
+
margin: 0 0 0.5rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
p {
|
|
115
|
+
margin: 0 0 0.5rem;
|
|
116
|
+
font-style: italic;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
</style>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="UluFacetsFilters">
|
|
3
|
+
<UluCollapsibleRegion
|
|
4
|
+
class="UluFacets__group"
|
|
5
|
+
:class="classes.group"
|
|
6
|
+
:classToggle="['UluFacets__group-toggle', classes.groupToggle]"
|
|
7
|
+
:classContent="['UluFacets__group-content', classes.groupContent]"
|
|
8
|
+
v-for="group in facets"
|
|
9
|
+
:key="group.uid"
|
|
10
|
+
:group="group"
|
|
11
|
+
:startOpen="group.open"
|
|
12
|
+
:clickOutsideCloses="false"
|
|
13
|
+
:closeOnEscape="false"
|
|
14
|
+
:transitionHeight="true"
|
|
15
|
+
>
|
|
16
|
+
<template #toggle="{ isOpen }">
|
|
17
|
+
<slot name="groupToggle" :group="group" :isOpen="isOpen">
|
|
18
|
+
{{ group.name }}
|
|
19
|
+
</slot>
|
|
20
|
+
</template>
|
|
21
|
+
<template #default>
|
|
22
|
+
<UluFacetsList
|
|
23
|
+
:children="group.children.slice(0, maxVisible)"
|
|
24
|
+
:groupUid="group.uid"
|
|
25
|
+
:classFacet="classes.facet"
|
|
26
|
+
@facet-change="emit('facet-change', $event)"
|
|
27
|
+
/>
|
|
28
|
+
<UluCollapsibleRegion
|
|
29
|
+
v-if="group.children.length > maxVisible"
|
|
30
|
+
class="UluFacets__more-facets"
|
|
31
|
+
:class="classes.moreFacets"
|
|
32
|
+
:clickOutsideCloses="false"
|
|
33
|
+
:closeOnEscape="false"
|
|
34
|
+
:transitionHeight="true"
|
|
35
|
+
>
|
|
36
|
+
<template #toggle="{ isOpen }">
|
|
37
|
+
{{ isOpen ? "- Less" : "+ More" }}
|
|
38
|
+
</template>
|
|
39
|
+
<template #default>
|
|
40
|
+
<UluFacetsList
|
|
41
|
+
:children="group.children.slice(maxVisible)"
|
|
42
|
+
:groupUid="group.uid"
|
|
43
|
+
:classFacet="classes.facet"
|
|
44
|
+
@facet-change="emit('facet-change', $event)"
|
|
45
|
+
/>
|
|
46
|
+
</template>
|
|
47
|
+
</UluCollapsibleRegion>
|
|
48
|
+
</template>
|
|
49
|
+
</UluCollapsibleRegion>
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<script setup>
|
|
54
|
+
import UluFacetsList from "./UluFacetsList.vue";
|
|
55
|
+
import UluCollapsibleRegion from "../../collapsible/UluCollapsibleRegion.vue";
|
|
56
|
+
|
|
57
|
+
defineProps({
|
|
58
|
+
classes: {
|
|
59
|
+
type: Object,
|
|
60
|
+
default: () => ({})
|
|
61
|
+
},
|
|
62
|
+
maxVisible: {
|
|
63
|
+
type: Number,
|
|
64
|
+
default: 5
|
|
65
|
+
},
|
|
66
|
+
facets: {
|
|
67
|
+
type: Array,
|
|
68
|
+
default: () => []
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const emit = defineEmits(['facet-change']);
|
|
73
|
+
</script>
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
class="UluFacets__facet-checkbox"
|
|
11
11
|
:id="facetCheckboxId(facet)"
|
|
12
12
|
type="checkbox"
|
|
13
|
-
|
|
13
|
+
:checked="facet.selected"
|
|
14
|
+
@change="emit('facet-change', { groupUid, facetUid: facet.uid, selected: $event.target.checked })"
|
|
14
15
|
>
|
|
15
16
|
<label
|
|
16
17
|
class="UluFacets__facet-label"
|
|
@@ -22,18 +23,16 @@
|
|
|
22
23
|
</ul>
|
|
23
24
|
</template>
|
|
24
25
|
|
|
25
|
-
<script>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
}
|
|
26
|
+
<script setup>
|
|
27
|
+
const props = defineProps({
|
|
28
|
+
groupUid: String,
|
|
29
|
+
children: Array,
|
|
30
|
+
classFacet: String
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const emit = defineEmits(['facet-change']);
|
|
34
|
+
|
|
35
|
+
function facetCheckboxId(facet) {
|
|
36
|
+
return `facet-${props.groupUid}-${facet.uid}`;
|
|
38
37
|
}
|
|
39
38
|
</script>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="UluFacetsResults">
|
|
3
|
+
<transition-group
|
|
4
|
+
v-if="items.length"
|
|
5
|
+
:tag="tag"
|
|
6
|
+
:name="transitionName"
|
|
7
|
+
class="UluFacetsResults__list"
|
|
8
|
+
>
|
|
9
|
+
<li
|
|
10
|
+
class="UluFacetsResults__item"
|
|
11
|
+
v-for="(item, index) in items"
|
|
12
|
+
:key="item.id || index"
|
|
13
|
+
>
|
|
14
|
+
<slot name="item" :item="item" :index="index"></slot>
|
|
15
|
+
</li>
|
|
16
|
+
</transition-group>
|
|
17
|
+
<div v-else class="UluFacetsResults__empty">
|
|
18
|
+
<slot name="empty">
|
|
19
|
+
<p>No matching items found.</p>
|
|
20
|
+
</slot>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup>
|
|
26
|
+
defineProps({
|
|
27
|
+
items: {
|
|
28
|
+
type: Array,
|
|
29
|
+
required: true
|
|
30
|
+
},
|
|
31
|
+
tag: {
|
|
32
|
+
type: String,
|
|
33
|
+
default: 'ul'
|
|
34
|
+
},
|
|
35
|
+
transitionName: {
|
|
36
|
+
type: String,
|
|
37
|
+
default: 'UluFacetsFade'
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<style lang="scss">
|
|
43
|
+
.UluFacetsResults__list {
|
|
44
|
+
list-style: none;
|
|
45
|
+
padding: 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.UluFacetsFade-enter-active,
|
|
49
|
+
.UluFacetsFade-leave-active {
|
|
50
|
+
transition: opacity 0.25s ease;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.UluFacetsFade-enter-from,
|
|
54
|
+
.UluFacetsFade-leave-to {
|
|
55
|
+
opacity: 0;
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
@@ -10,58 +10,35 @@
|
|
|
10
10
|
type="text"
|
|
11
11
|
:placeholder="placeholder"
|
|
12
12
|
>
|
|
13
|
-
<!-- <button
|
|
14
|
-
v-if="value"
|
|
15
|
-
:class="classes.searchClear"
|
|
16
|
-
@click="clear"
|
|
17
|
-
:aria-label="classes.searchClearIcon ? 'Clear Search' : false"
|
|
18
|
-
type="button"
|
|
19
|
-
>
|
|
20
|
-
<span
|
|
21
|
-
v-if="classes.searchClearIcon"
|
|
22
|
-
:class="classes.searchClearIcon"
|
|
23
|
-
aria-hidden="true"
|
|
24
|
-
></span>
|
|
25
|
-
<span v-else>
|
|
26
|
-
Clear
|
|
27
|
-
</span>
|
|
28
|
-
</button> -->
|
|
29
13
|
</div>
|
|
30
14
|
</template>
|
|
31
15
|
|
|
32
|
-
<script>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
placeholder: {
|
|
40
|
-
type: String,
|
|
41
|
-
default: "Keywords…"
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
data() {
|
|
45
|
-
return {
|
|
46
|
-
id: `facet-view-keyword-${ ++uid }`
|
|
47
|
-
}
|
|
16
|
+
<script setup>
|
|
17
|
+
import { computed } from 'vue';
|
|
18
|
+
|
|
19
|
+
const props = defineProps({
|
|
20
|
+
classes: {
|
|
21
|
+
type: Object,
|
|
22
|
+
default: () => ({})
|
|
48
23
|
},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
24
|
+
modelValue: String,
|
|
25
|
+
placeholder: {
|
|
26
|
+
type: String,
|
|
27
|
+
default: "Keywords…"
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const emit = defineEmits(['update:modelValue']);
|
|
32
|
+
|
|
33
|
+
let uid = 0;
|
|
34
|
+
const id = `facet-view-keyword-${++uid}`;
|
|
35
|
+
|
|
36
|
+
const localValue = computed({
|
|
37
|
+
get() {
|
|
38
|
+
return props.modelValue;
|
|
58
39
|
},
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// this.value = null;
|
|
62
|
-
// this.applied = false;
|
|
63
|
-
// this.$emit("search", null);
|
|
64
|
-
}
|
|
40
|
+
set(val) {
|
|
41
|
+
emit('update:modelValue', val);
|
|
65
42
|
}
|
|
66
|
-
}
|
|
67
|
-
</script>
|
|
43
|
+
});
|
|
44
|
+
</script>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="UluFacetsSidebarLayout">
|
|
3
|
+
<div class="UluFacetsSidebarLayout__header">
|
|
4
|
+
<slot name="header"></slot>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="UluFacetsSidebarLayout__body">
|
|
7
|
+
<div class="UluFacetsSidebarLayout__sidebar">
|
|
8
|
+
<slot name="sidebar"></slot>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="UluFacetsSidebarLayout__main">
|
|
11
|
+
<slot name="main"></slot>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup>
|
|
18
|
+
// This component is purely for layout, no logic needed.
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<style lang="scss">
|
|
22
|
+
.UluFacetsSidebarLayout__body {
|
|
23
|
+
display: grid;
|
|
24
|
+
grid-template-columns: 1fr;
|
|
25
|
+
gap: 2rem;
|
|
26
|
+
|
|
27
|
+
@media (min-width: 768px) {
|
|
28
|
+
grid-template-columns: 250px 1fr;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
</style>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="UluFacetsSort" :class="classes.sortForm">
|
|
3
|
+
<label
|
|
4
|
+
:for="sortId"
|
|
5
|
+
:class="classes.sortFormLabel"
|
|
6
|
+
>
|
|
7
|
+
<slot>Sort:</slot>
|
|
8
|
+
</label>
|
|
9
|
+
<select
|
|
10
|
+
:value="modelValue"
|
|
11
|
+
@change="emit('update:modelValue', $event.target.value)"
|
|
12
|
+
:id="sortId"
|
|
13
|
+
:class="classes.sortFormSelect"
|
|
14
|
+
>
|
|
15
|
+
<option v-for="(item, key) in sortTypes" :value="key" :key="key">
|
|
16
|
+
{{ item.text }}
|
|
17
|
+
</option>
|
|
18
|
+
</select>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup>
|
|
23
|
+
import { ref } from 'vue';
|
|
24
|
+
|
|
25
|
+
let idCounter = 0;
|
|
26
|
+
|
|
27
|
+
defineProps({
|
|
28
|
+
classes: {
|
|
29
|
+
type: Object,
|
|
30
|
+
default: () => ({})
|
|
31
|
+
},
|
|
32
|
+
sortTypes: {
|
|
33
|
+
type: Object,
|
|
34
|
+
default: () => ({})
|
|
35
|
+
},
|
|
36
|
+
modelValue: {
|
|
37
|
+
type: String,
|
|
38
|
+
default: ''
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const emit = defineEmits(['update:modelValue']);
|
|
43
|
+
|
|
44
|
+
const sortId = ref(`ulu-facet-sort-${++idCounter}`);
|
|
45
|
+
</script>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const initialMockFacets = [
|
|
2
|
+
{
|
|
3
|
+
name: 'Category',
|
|
4
|
+
uid: 'category',
|
|
5
|
+
open: true,
|
|
6
|
+
children: [
|
|
7
|
+
{ uid: 'cat1', label: 'Design' },
|
|
8
|
+
{ uid: 'cat2', label: 'Development' },
|
|
9
|
+
{ uid: 'cat3', label: 'Marketing' },
|
|
10
|
+
{ uid: 'cat4', label: 'Business' },
|
|
11
|
+
{ uid: 'cat5', label: 'Lifestyle' },
|
|
12
|
+
{ uid: 'cat6', label: 'Technology' },
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'Author',
|
|
17
|
+
uid: 'author',
|
|
18
|
+
open: true,
|
|
19
|
+
children: [
|
|
20
|
+
{ uid: 'jane-doe', label: 'Jane Doe' },
|
|
21
|
+
{ uid: 'john-smith', label: 'John Smith' },
|
|
22
|
+
{ uid: 'peter-jones', label: 'Peter Jones' },
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export const mockItems = [
|
|
28
|
+
{ id: 1, title: 'The Art of UI Design', description: 'A deep dive into creating beautiful user interfaces.', category: ['cat1', 'cat2'], author: ['jane-doe'], date: new Date(2023, 5, 15) },
|
|
29
|
+
{ id: 2, title: 'Vue.js for Beginners', description: 'Getting started with the popular JavaScript framework.', category: ['cat2', 'cat6'], author: ['john-smith'], date: new Date(2023, 8, 22) },
|
|
30
|
+
{ id: 3, title: 'Content Marketing Strategies', description: 'How to attract and retain customers with great content.', category: ['cat3'], author: ['peter-jones'], date: new Date(2022, 11, 10) },
|
|
31
|
+
{ id: 4, title: 'Startup Funding 101', description: 'A guide to raising capital for your new venture.', category: ['cat4'], author: ['jane-doe'], date: new Date(2024, 1, 5) },
|
|
32
|
+
{ id: 5, title: 'Minimalist Living', description: 'Declutter your life and find more happiness.', category: ['cat5'], author: ['john-smith'], date: new Date(2023, 3, 30) },
|
|
33
|
+
{ id: 6, title: 'The Future of AI', description: 'Exploring the impact of artificial intelligence on society.', category: ['cat6'], author: ['peter-jones'], date: new Date(2024, 0, 1) },
|
|
34
|
+
{ id: 7, title: 'Advanced CSS Techniques', description: 'Take your styling skills to the next level.', category: ['cat1', 'cat2'], author: ['jane-doe'], date: new Date(2023, 10, 18) },
|
|
35
|
+
{ id: 8, title: 'Building a Scalable API', description: 'Best practices for designing and implementing APIs.', category: ['cat2', 'cat6'], author: ['john-smith'], date: new Date(2023, 7, 3) },
|
|
36
|
+
{ id: 9, title: 'Social Media for Business', description: 'Leveraging social platforms for growth.', category: ['cat3'], author: ['peter-jones'], date: new Date(2022, 9, 14) },
|
|
37
|
+
{ id: 10, title: 'Negotiation and Deal Making', description: 'Master the art of getting what you want.', category: ['cat4'], author: ['jane-doe'], date: new Date(2023, 6, 25) },
|
|
38
|
+
{ id: 11, title: 'Healthy Eating Habits', description: 'A guide to a balanced and nutritious diet.', category: ['cat5'], author: ['john-smith'], date: new Date(2024, 2, 12) },
|
|
39
|
+
{ id: 12, title: 'Quantum Computing Explained', description: 'A simple introduction to a complex topic.', category: ['cat6'], author: ['peter-jones'], date: new Date(2023, 9, 9) },
|
|
40
|
+
];
|