picocrank 1.12.5 → 1.13.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 +1 -1
- package/vue/components/Header.vue +11 -0
- package/vue/components/TopBar.vue +132 -0
- package/vue/views/App.vue +28 -11
- package/vue/views/Welcome.vue +19 -5
package/package.json
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
</button>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
14
|
+
<TopBar v-if="topBarEnabled" :navigation="navigation" />
|
|
15
|
+
|
|
14
16
|
<Breadcrumbs v-if="breadcrumbs" />
|
|
15
17
|
|
|
16
18
|
<slot name="toolbar" />
|
|
@@ -30,6 +32,7 @@
|
|
|
30
32
|
import { Menu01Icon } from "@hugeicons/core-free-icons";
|
|
31
33
|
|
|
32
34
|
import Breadcrumbs from "./Breadcrumbs.vue";
|
|
35
|
+
import TopBar from "./TopBar.vue";
|
|
33
36
|
|
|
34
37
|
const emit = defineEmits(["toggleSidebar"]);
|
|
35
38
|
|
|
@@ -54,6 +57,14 @@
|
|
|
54
57
|
type: Boolean,
|
|
55
58
|
default: true,
|
|
56
59
|
},
|
|
60
|
+
topBarEnabled: {
|
|
61
|
+
type: Boolean,
|
|
62
|
+
default: false,
|
|
63
|
+
},
|
|
64
|
+
navigation: {
|
|
65
|
+
type: Object,
|
|
66
|
+
default: null,
|
|
67
|
+
},
|
|
57
68
|
});
|
|
58
69
|
</script>
|
|
59
70
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<nav class="topbar">
|
|
3
|
+
<div class="topbar-links flex-row">
|
|
4
|
+
<template v-for="link in navigationLinks" :key="link.name">
|
|
5
|
+
<!-- Render separator as a divider -->
|
|
6
|
+
<div v-if="link.type === 'separator'" class="separator"></div>
|
|
7
|
+
<!-- Render callback link -->
|
|
8
|
+
<a v-else-if="link.type === 'callback'" href="#" @click.prevent="handleLinkClick(() => link.callback())" class="button topbar-link">
|
|
9
|
+
<HugeiconsIcon :icon="link.icon" width="1em" height="1em" />
|
|
10
|
+
<span>{{ link.title }}</span>
|
|
11
|
+
</a>
|
|
12
|
+
<!-- Render HTML content -->
|
|
13
|
+
<div v-else-if="link.type === 'html'" v-html="link.html" class="topbar-html"></div>
|
|
14
|
+
<!-- Render router link -->
|
|
15
|
+
<router-link v-else v-bind="link.props || {}" :to="link.to || link.path" :class="['button', 'topbar-link', { active: isActive(link) }]">
|
|
16
|
+
<HugeiconsIcon :icon="link.icon" width="1em" height="1em" />
|
|
17
|
+
<span>{{ link.title }}</span>
|
|
18
|
+
</router-link>
|
|
19
|
+
</template>
|
|
20
|
+
</div>
|
|
21
|
+
</nav>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script setup>
|
|
25
|
+
import { computed, inject } from 'vue'
|
|
26
|
+
import { HugeiconsIcon } from '@hugeicons/vue'
|
|
27
|
+
|
|
28
|
+
const props = defineProps({
|
|
29
|
+
navigation: {
|
|
30
|
+
type: Object,
|
|
31
|
+
default: null
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// Try to get navigation from inject first, fall back to prop
|
|
36
|
+
const injectedNavigation = inject('navigation', null)
|
|
37
|
+
|
|
38
|
+
// Get navigation object - handle both component ref and direct object
|
|
39
|
+
const navigation = computed(() => {
|
|
40
|
+
const nav = props.navigation || injectedNavigation
|
|
41
|
+
if (!nav) return null
|
|
42
|
+
|
|
43
|
+
// If it's a component ref, access its exposed API
|
|
44
|
+
if (nav.value) {
|
|
45
|
+
return nav.value
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Otherwise, assume it's the navigation object directly
|
|
49
|
+
return nav
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// Get navigation links and isActive function from navigation
|
|
53
|
+
// navigationLinks is a ref, so we return it directly (Vue will unwrap it in template)
|
|
54
|
+
const navigationLinks = computed(() => {
|
|
55
|
+
const nav = navigation.value
|
|
56
|
+
if (!nav || !nav.navigationLinks) {
|
|
57
|
+
return []
|
|
58
|
+
}
|
|
59
|
+
// Return the ref itself - Vue will unwrap it in the template
|
|
60
|
+
return nav.navigationLinks
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// Get isActive function - create a function that accesses the navigation computed
|
|
64
|
+
function isActive(link) {
|
|
65
|
+
const nav = navigation.value
|
|
66
|
+
if (!nav || !nav.isActive) {
|
|
67
|
+
return false
|
|
68
|
+
}
|
|
69
|
+
return nav.isActive(link)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function handleLinkClick(callback = null) {
|
|
73
|
+
if (callback) {
|
|
74
|
+
callback()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<style scoped>
|
|
80
|
+
.topbar {
|
|
81
|
+
width: 100%;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.topbar-links {
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
gap: 0.125rem;
|
|
88
|
+
flex-wrap: wrap;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.topbar-link {
|
|
92
|
+
display: flex;
|
|
93
|
+
align-items: center;
|
|
94
|
+
gap: 0.375rem;
|
|
95
|
+
padding: 0.5em 0.75em;
|
|
96
|
+
border-radius: 0.25em;
|
|
97
|
+
text-decoration: none;
|
|
98
|
+
color: inherit;
|
|
99
|
+
transition: background-color 0.15s ease;
|
|
100
|
+
white-space: nowrap;
|
|
101
|
+
border: 0;
|
|
102
|
+
font-weight: normal;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.topbar-link.active {
|
|
106
|
+
text-decoration: underline;
|
|
107
|
+
font-weight: 500;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.topbar-html {
|
|
111
|
+
display: flex;
|
|
112
|
+
align-items: center;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.separator {
|
|
116
|
+
width: 1px;
|
|
117
|
+
height: 1.5em;
|
|
118
|
+
background-color: currentColor;
|
|
119
|
+
opacity: 0.3;
|
|
120
|
+
margin: 0 0.125rem;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@media (prefers-color-scheme: dark) {
|
|
124
|
+
.topbar-link {
|
|
125
|
+
color: #f8f9fa;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.separator {
|
|
129
|
+
opacity: 0.5;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
</style>
|
package/vue/views/App.vue
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<Header username = "Guest" @toggleSidebar="toggleSidebar" title = "PicoCrank" :logoUrl="logoUrl" :sidebarEnabled="sidebarEnabled">
|
|
2
|
+
<Header username = "Guest" @toggleSidebar="toggleSidebar" title = "PicoCrank" :logoUrl="logoUrl" :sidebarEnabled="sidebarEnabled" :navigation="navigation" :topBarEnabled="topBarEnabled">
|
|
3
3
|
<template #toolbar>
|
|
4
4
|
<QuickSearch
|
|
5
|
+
v-if="quickSearchEnabled"
|
|
5
6
|
ref="quickSearchRef"
|
|
6
7
|
placeholder="Search items..."
|
|
7
8
|
:search-fields="['title', 'name']"
|
|
@@ -42,6 +43,8 @@
|
|
|
42
43
|
const sidebar = ref(null);
|
|
43
44
|
const navigation = ref(null);
|
|
44
45
|
const sidebarEnabled = ref(true);
|
|
46
|
+
const quickSearchEnabled = ref(true);
|
|
47
|
+
const topBarEnabled = ref(false);
|
|
45
48
|
|
|
46
49
|
function toggleSidebar() {
|
|
47
50
|
if (sidebar.value) {
|
|
@@ -53,9 +56,21 @@
|
|
|
53
56
|
sidebarEnabled.value = !sidebarEnabled.value;
|
|
54
57
|
}
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
function toggleQuickSearchEnabled() {
|
|
60
|
+
quickSearchEnabled.value = !quickSearchEnabled.value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function toggleTopBarEnabled() {
|
|
64
|
+
topBarEnabled.value = !topBarEnabled.value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Provide sidebar, QuickSearch, and TopBar state and toggle functions for child components
|
|
57
68
|
provide('sidebarEnabled', sidebarEnabled);
|
|
58
69
|
provide('toggleSidebarEnabled', toggleSidebarEnabled);
|
|
70
|
+
provide('quickSearchEnabled', quickSearchEnabled);
|
|
71
|
+
provide('toggleQuickSearchEnabled', toggleQuickSearchEnabled);
|
|
72
|
+
provide('topBarEnabled', topBarEnabled);
|
|
73
|
+
provide('toggleTopBarEnabled', toggleTopBarEnabled);
|
|
59
74
|
|
|
60
75
|
onMounted(() => {
|
|
61
76
|
if (navigation.value) {
|
|
@@ -84,15 +99,17 @@
|
|
|
84
99
|
sidebar.value.stick();
|
|
85
100
|
}
|
|
86
101
|
|
|
87
|
-
quickSearchRef.value
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
102
|
+
if (quickSearchRef.value) {
|
|
103
|
+
quickSearchRef.value.addItem({
|
|
104
|
+
id: 'hello-world',
|
|
105
|
+
title: 'Hello World',
|
|
106
|
+
name: 'hello-world',
|
|
107
|
+
description: 'This is a test item',
|
|
108
|
+
category: 'Actions',
|
|
109
|
+
type: 'callback',
|
|
110
|
+
callback: helloWorld
|
|
111
|
+
})
|
|
112
|
+
}
|
|
96
113
|
});
|
|
97
114
|
|
|
98
115
|
function helloWorld() {
|
package/vue/views/Welcome.vue
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Section title = "Welcome" classes = "">
|
|
3
3
|
<template #toolbar>
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
<div style="display: flex; gap: 1rem; align-items: center;">
|
|
5
|
+
<label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
|
|
6
|
+
<input type="checkbox" :checked="sidebarEnabled" @change="toggleSidebarEnabled" />
|
|
7
|
+
<span>Enable Sidebar</span>
|
|
8
|
+
</label>
|
|
9
|
+
<label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
|
|
10
|
+
<input type="checkbox" :checked="quickSearchEnabled" @change="toggleQuickSearchEnabled" />
|
|
11
|
+
<span>Enable QuickSearch</span>
|
|
12
|
+
</label>
|
|
13
|
+
<label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
|
|
14
|
+
<input type="checkbox" :checked="topBarEnabled" @change="toggleTopBarEnabled" />
|
|
15
|
+
<span>Enable TopBar</span>
|
|
16
|
+
</label>
|
|
17
|
+
</div>
|
|
8
18
|
</template>
|
|
9
19
|
<p>
|
|
10
20
|
Welcome to Femtocrank, a web-based tool for analyzing and visualizing the performance of your code.
|
|
@@ -83,7 +93,11 @@
|
|
|
83
93
|
import { HighlighterIcon } from '@hugeicons/core-free-icons';
|
|
84
94
|
import { Menu01Icon } from '@hugeicons/core-free-icons';
|
|
85
95
|
|
|
86
|
-
// Inject sidebar state and toggle
|
|
96
|
+
// Inject sidebar, QuickSearch, and TopBar state and toggle functions from App.vue
|
|
87
97
|
const sidebarEnabled = inject('sidebarEnabled');
|
|
88
98
|
const toggleSidebarEnabled = inject('toggleSidebarEnabled');
|
|
99
|
+
const quickSearchEnabled = inject('quickSearchEnabled');
|
|
100
|
+
const toggleQuickSearchEnabled = inject('toggleQuickSearchEnabled');
|
|
101
|
+
const topBarEnabled = inject('topBarEnabled');
|
|
102
|
+
const toggleTopBarEnabled = inject('toggleTopBarEnabled');
|
|
89
103
|
</script>
|