picocrank 1.27.0 → 1.28.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/package.json
CHANGED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import { createRouter, createMemoryHistory } from 'vue-router'
|
|
4
|
+
import Header from './Header.vue'
|
|
5
|
+
|
|
6
|
+
const router = createRouter({
|
|
7
|
+
history: createMemoryHistory(),
|
|
8
|
+
routes: [
|
|
9
|
+
{ path: '/login', name: 'Login', component: { template: '<div>Login</div>' } },
|
|
10
|
+
],
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const globalStubs = {
|
|
14
|
+
HugeiconsIcon: true,
|
|
15
|
+
Breadcrumbs: true,
|
|
16
|
+
TopBar: true,
|
|
17
|
+
Sidebar: true,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('Header loginRoute', () => {
|
|
21
|
+
it('shows a Login link when username is empty and loginRoute is set', async () => {
|
|
22
|
+
const wrapper = mount(Header, {
|
|
23
|
+
props: {
|
|
24
|
+
username: '',
|
|
25
|
+
loginRoute: { name: 'Login' },
|
|
26
|
+
sidebarEnabled: false,
|
|
27
|
+
},
|
|
28
|
+
global: {
|
|
29
|
+
plugins: [router],
|
|
30
|
+
stubs: globalStubs,
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const loginLink = wrapper.find('a.login-link')
|
|
35
|
+
expect(loginLink.exists()).toBe(true)
|
|
36
|
+
expect(loginLink.text()).toBe('Login')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('shows the username control instead of Login when username is set', () => {
|
|
40
|
+
const wrapper = mount(Header, {
|
|
41
|
+
props: {
|
|
42
|
+
username: 'tester',
|
|
43
|
+
loginRoute: { name: 'Login' },
|
|
44
|
+
sidebarEnabled: false,
|
|
45
|
+
},
|
|
46
|
+
global: {
|
|
47
|
+
plugins: [router],
|
|
48
|
+
stubs: globalStubs,
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
expect(wrapper.find('a.login-link').exists()).toBe(false)
|
|
53
|
+
expect(wrapper.find('.user-info span').text()).toBe('tester')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('shows neither Login nor username when loginRoute is not set', () => {
|
|
57
|
+
const wrapper = mount(Header, {
|
|
58
|
+
props: {
|
|
59
|
+
username: '',
|
|
60
|
+
sidebarEnabled: false,
|
|
61
|
+
},
|
|
62
|
+
global: {
|
|
63
|
+
plugins: [router],
|
|
64
|
+
stubs: globalStubs,
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
expect(wrapper.find('a.login-link').exists()).toBe(false)
|
|
69
|
+
expect(wrapper.find('.user-info').exists()).toBe(false)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
@@ -55,6 +55,13 @@
|
|
|
55
55
|
<HugeiconsIcon :icon="UserIcon" width="1em" height="1em" aria-hidden="true" />
|
|
56
56
|
<span>{{ username }}</span>
|
|
57
57
|
</button>
|
|
58
|
+
<RouterLink
|
|
59
|
+
v-else-if="showLoginLink"
|
|
60
|
+
:to="loginRoute"
|
|
61
|
+
class="user-info flex-row neutral login-link"
|
|
62
|
+
>
|
|
63
|
+
<span>Login</span>
|
|
64
|
+
</RouterLink>
|
|
58
65
|
</slot>
|
|
59
66
|
</div>
|
|
60
67
|
</header>
|
|
@@ -65,6 +72,7 @@
|
|
|
65
72
|
|
|
66
73
|
<script setup>
|
|
67
74
|
import { computed, ref } from "vue";
|
|
75
|
+
import { RouterLink } from "vue-router";
|
|
68
76
|
import { HugeiconsIcon } from "@hugeicons/vue";
|
|
69
77
|
import { BulbIcon, Menu01Icon, Moon02Icon, Sun01Icon, UserIcon } from "@hugeicons/core-free-icons";
|
|
70
78
|
|
|
@@ -110,6 +118,10 @@
|
|
|
110
118
|
type: String,
|
|
111
119
|
default: "",
|
|
112
120
|
},
|
|
121
|
+
loginRoute: {
|
|
122
|
+
type: [String, Object],
|
|
123
|
+
default: null,
|
|
124
|
+
},
|
|
113
125
|
title: {
|
|
114
126
|
type: String,
|
|
115
127
|
default: "Untitled",
|
|
@@ -155,6 +167,10 @@
|
|
|
155
167
|
() => props.breadcrumbs && !isMobile.value,
|
|
156
168
|
);
|
|
157
169
|
|
|
170
|
+
const showLoginLink = computed(
|
|
171
|
+
() => !props.username.trim() && props.loginRoute != null && props.loginRoute !== '',
|
|
172
|
+
);
|
|
173
|
+
|
|
158
174
|
function toggleNavSidebar() {
|
|
159
175
|
if (needsFallbackSidebar.value) {
|
|
160
176
|
fallbackSidebar.value?.toggle();
|
|
@@ -201,6 +217,11 @@
|
|
|
201
217
|
font-weight: normal;
|
|
202
218
|
}
|
|
203
219
|
|
|
220
|
+
.login-link {
|
|
221
|
+
text-decoration: none;
|
|
222
|
+
color: inherit;
|
|
223
|
+
}
|
|
224
|
+
|
|
204
225
|
.user-info span {
|
|
205
226
|
padding-right: 0;
|
|
206
227
|
font-weight: normal;
|
|
@@ -218,6 +239,7 @@
|
|
|
218
239
|
|
|
219
240
|
/* Match Femtocrank header chrome (same idea as #sidebar-button:hover) */
|
|
220
241
|
.header-actions > button,
|
|
242
|
+
.header-actions > a.login-link,
|
|
221
243
|
.header-actions :deep(button) {
|
|
222
244
|
border: 0;
|
|
223
245
|
border-radius: 0;
|
|
@@ -233,6 +255,7 @@
|
|
|
233
255
|
}
|
|
234
256
|
|
|
235
257
|
.header-actions > button:hover,
|
|
258
|
+
.header-actions > a.login-link:hover,
|
|
236
259
|
.header-actions :deep(button:hover),
|
|
237
260
|
.user-info:hover {
|
|
238
261
|
background-color: var(--header-hover-background-color);
|
|
@@ -298,4 +321,8 @@ header .search-trigger:hover {
|
|
|
298
321
|
header .user-info {
|
|
299
322
|
font-weight: normal;
|
|
300
323
|
}
|
|
324
|
+
|
|
325
|
+
header .login-link {
|
|
326
|
+
font-weight: normal;
|
|
327
|
+
}
|
|
301
328
|
</style>
|
package/vue/examples/App.vue
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
<Navigation ref="navigation">
|
|
3
3
|
<Navigation ref="topBarNavigation">
|
|
4
4
|
<Header
|
|
5
|
-
username="
|
|
5
|
+
:username="headerUsername"
|
|
6
|
+
:login-route="headerLoginRoute"
|
|
6
7
|
@toggleSidebar="toggleSidebar"
|
|
7
8
|
@logoClick="goToIndex"
|
|
8
9
|
@userClick="goToUserDetails"
|
|
@@ -85,6 +86,8 @@
|
|
|
85
86
|
const includeSupplementalThemes = ref(true);
|
|
86
87
|
const topBarEnabled = ref(false);
|
|
87
88
|
const breadcrumbsEnabled = ref(true);
|
|
89
|
+
const headerUsername = ref('tester');
|
|
90
|
+
const headerLoginRoute = { name: 'Login' };
|
|
88
91
|
|
|
89
92
|
const { discoverThemes } = initCustomTheme({ includeSupplementalThemes: true });
|
|
90
93
|
|
|
@@ -134,6 +137,10 @@
|
|
|
134
137
|
breadcrumbsEnabled.value = !breadcrumbsEnabled.value;
|
|
135
138
|
}
|
|
136
139
|
|
|
140
|
+
function setHeaderUsername(username) {
|
|
141
|
+
headerUsername.value = username;
|
|
142
|
+
}
|
|
143
|
+
|
|
137
144
|
async function dummyFetchResults(_query, { signal } = {}) {
|
|
138
145
|
await new Promise((resolve, reject) => {
|
|
139
146
|
const timer = setTimeout(resolve, 1500)
|
|
@@ -200,6 +207,8 @@
|
|
|
200
207
|
provide('toggleTopBarEnabled', toggleTopBarEnabled);
|
|
201
208
|
provide('breadcrumbsEnabled', breadcrumbsEnabled);
|
|
202
209
|
provide('toggleBreadcrumbsEnabled', toggleBreadcrumbsEnabled);
|
|
210
|
+
provide('headerUsername', headerUsername);
|
|
211
|
+
provide('setHeaderUsername', setHeaderUsername);
|
|
203
212
|
|
|
204
213
|
watch(quickSearchRef, (quickSearch) => {
|
|
205
214
|
if (quickSearch) {
|
|
@@ -102,6 +102,23 @@
|
|
|
102
102
|
@update:model-value="setBreadcrumbsEnabled"
|
|
103
103
|
/>
|
|
104
104
|
</FormField>
|
|
105
|
+
|
|
106
|
+
<FormField label="Header username" component-has-label>
|
|
107
|
+
<div>
|
|
108
|
+
<RadioGroup
|
|
109
|
+
name="ps-header-username"
|
|
110
|
+
variant="list"
|
|
111
|
+
aria-label="Header username"
|
|
112
|
+
:model-value="headerUsername"
|
|
113
|
+
:options="headerUsernameOptions"
|
|
114
|
+
@update:model-value="setHeaderUsernameValue"
|
|
115
|
+
/>
|
|
116
|
+
<p class="subtle">
|
|
117
|
+
When no username is set, the header shows a Login link if
|
|
118
|
+
<code>loginRoute</code> is configured.
|
|
119
|
+
</p>
|
|
120
|
+
</div>
|
|
121
|
+
</FormField>
|
|
105
122
|
</FormLayout>
|
|
106
123
|
</Section>
|
|
107
124
|
|
|
@@ -174,6 +191,11 @@ const onOffOptions = [
|
|
|
174
191
|
{ label: 'Off', value: false },
|
|
175
192
|
]
|
|
176
193
|
|
|
194
|
+
const headerUsernameOptions = [
|
|
195
|
+
{ label: 'No username', value: '' },
|
|
196
|
+
{ label: 'tester', value: 'tester' },
|
|
197
|
+
]
|
|
198
|
+
|
|
177
199
|
const sidebarEnabled = inject('sidebarEnabled')
|
|
178
200
|
const toggleSidebarEnabled = inject('toggleSidebarEnabled')
|
|
179
201
|
const brandingEnabled = inject('brandingEnabled')
|
|
@@ -190,6 +212,8 @@ const topBarEnabled = inject('topBarEnabled')
|
|
|
190
212
|
const toggleTopBarEnabled = inject('toggleTopBarEnabled')
|
|
191
213
|
const breadcrumbsEnabled = inject('breadcrumbsEnabled')
|
|
192
214
|
const toggleBreadcrumbsEnabled = inject('toggleBreadcrumbsEnabled')
|
|
215
|
+
const headerUsername = inject('headerUsername')
|
|
216
|
+
const setHeaderUsername = inject('setHeaderUsername')
|
|
193
217
|
const navigation = inject('navigation', null)
|
|
194
218
|
|
|
195
219
|
const exampleLinksEnabled = ref(false)
|
|
@@ -228,6 +252,10 @@ function setBreadcrumbsEnabled(want) {
|
|
|
228
252
|
setFlag(breadcrumbsEnabled, toggleBreadcrumbsEnabled, want)
|
|
229
253
|
}
|
|
230
254
|
|
|
255
|
+
function setHeaderUsernameValue(username) {
|
|
256
|
+
setHeaderUsername(username)
|
|
257
|
+
}
|
|
258
|
+
|
|
231
259
|
function setSidebarEnabled(want) {
|
|
232
260
|
setFlag(sidebarEnabled, toggleSidebarEnabled, want)
|
|
233
261
|
}
|