picocrank 1.8.8 → 1.9.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/.github/workflows/pages.yml +2 -3
- package/README.md +1 -1
- package/package.json +4 -4
- package/vite.config.js +1 -1
- package/vue/components/Calendar.vue +26 -1
- package/vue/components/Sidebar.vue +49 -2
|
@@ -24,8 +24,7 @@ jobs:
|
|
|
24
24
|
- name: Setup Node.js
|
|
25
25
|
uses: actions/setup-node@v4
|
|
26
26
|
with:
|
|
27
|
-
node-version: "
|
|
28
|
-
cache: 'npm'
|
|
27
|
+
node-version: "22"
|
|
29
28
|
|
|
30
29
|
- name: Install dependencies
|
|
31
30
|
run: npm ci
|
|
@@ -50,4 +49,4 @@ jobs:
|
|
|
50
49
|
steps:
|
|
51
50
|
- name: Deploy to GitHub Pages
|
|
52
51
|
id: deployment
|
|
53
|
-
uses: actions/deploy-pages@v4
|
|
52
|
+
uses: actions/deploy-pages@v4
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<img alt = "project logo" src = "logo.png" width = "128" />
|
|
3
3
|
<h1>PicoCrank</h1>
|
|
4
4
|
|
|
5
|
-
A set of
|
|
5
|
+
A lightweight set of Vue components built on the [FemtoCrank](https://github.com/jamesread/femtocrank) global CSS theme.
|
|
6
6
|
|
|
7
7
|
[](#none)
|
|
8
8
|
[](https://discord.gg/jhYWWpNJ3v)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "picocrank",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "A set of zero dependency Vue components built on the Femtocrank global CSS theme.",
|
|
5
5
|
"main": "vite.config.js",
|
|
6
6
|
"scripts": {
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
"url": "https://github.com/jamesread/picocrank/issues"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@hugeicons/core-free-icons": "^
|
|
21
|
+
"@hugeicons/core-free-icons": "^2.0.0",
|
|
22
22
|
"@hugeicons/vue": "^1.0.3",
|
|
23
|
-
"@vitejs/plugin-vue": "^6.0.
|
|
23
|
+
"@vitejs/plugin-vue": "^6.0.2",
|
|
24
24
|
"femtocrank": "^2.4.11",
|
|
25
25
|
"unplugin-vue-components": "^30.0.0",
|
|
26
|
-
"vite": "^7.2.
|
|
26
|
+
"vite": "^7.2.4",
|
|
27
27
|
"vue": "^3.5.24",
|
|
28
28
|
"vue-router": "^4.6.3"
|
|
29
29
|
},
|
package/vite.config.js
CHANGED
|
@@ -203,6 +203,22 @@ function formatEventTimeDefault(event: CalendarEvent, date: Date): string {
|
|
|
203
203
|
return 'All day'
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
// Get ordinal suffix for a number (1st, 2nd, 3rd, 4th, etc.)
|
|
207
|
+
function getOrdinalSuffix(day: number): string {
|
|
208
|
+
const j = day % 10
|
|
209
|
+
const k = day % 100
|
|
210
|
+
if (j === 1 && k !== 11) {
|
|
211
|
+
return 'st'
|
|
212
|
+
}
|
|
213
|
+
if (j === 2 && k !== 12) {
|
|
214
|
+
return 'nd'
|
|
215
|
+
}
|
|
216
|
+
if (j === 3 && k !== 13) {
|
|
217
|
+
return 'rd'
|
|
218
|
+
}
|
|
219
|
+
return 'th'
|
|
220
|
+
}
|
|
221
|
+
|
|
206
222
|
// Calendar generation from persistent grid start
|
|
207
223
|
const calendarDays = computed(() => {
|
|
208
224
|
const days = [] as { date: Date; events: CalendarEvent[] }[]
|
|
@@ -355,7 +371,7 @@ watch([currentMonth, currentYear], () => {
|
|
|
355
371
|
>
|
|
356
372
|
<div v-if="day" class="day-content" @click="handleDateClick(day.date)">
|
|
357
373
|
<div class="day-number clickable">
|
|
358
|
-
{{ day.date.getDate() }}
|
|
374
|
+
{{ day.date.getDate() }}<span class="day-month">{{ getOrdinalSuffix(day.date.getDate()) }} {{ monthNames[day.date.getMonth()].substring(0, 3) }}</span>
|
|
359
375
|
</div>
|
|
360
376
|
<div class="day-events">
|
|
361
377
|
<div
|
|
@@ -494,6 +510,10 @@ watch([currentMonth, currentYear], () => {
|
|
|
494
510
|
background-color: #f0f8ff;
|
|
495
511
|
}
|
|
496
512
|
|
|
513
|
+
.calendar-day:hover .day-number .day-month {
|
|
514
|
+
display: inline;
|
|
515
|
+
}
|
|
516
|
+
|
|
497
517
|
.calendar-day:nth-child(7n) {
|
|
498
518
|
border-right: none;
|
|
499
519
|
}
|
|
@@ -560,6 +580,11 @@ watch([currentMonth, currentYear], () => {
|
|
|
560
580
|
transition: background-color 0.2s;
|
|
561
581
|
}
|
|
562
582
|
|
|
583
|
+
.day-number.clickable .day-month {
|
|
584
|
+
display: none;
|
|
585
|
+
font-size: small;
|
|
586
|
+
}
|
|
587
|
+
|
|
563
588
|
.day-content:hover .day-number.clickable {
|
|
564
589
|
color: #007bff;
|
|
565
590
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<aside :class="{ 'shown': isOpen, 'stuck': isStuck }" class="sidebar">
|
|
2
|
+
<aside ref="sidebarRef" :class="{ 'shown': isOpen, 'stuck': isStuck }" class="sidebar">
|
|
3
3
|
<div class = "flex-row">
|
|
4
4
|
<h2>Navigation</h2>
|
|
5
5
|
<div class = "fg1" />
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
</template>
|
|
37
37
|
|
|
38
38
|
<script setup>
|
|
39
|
-
import { ref } from 'vue'
|
|
39
|
+
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'
|
|
40
40
|
import { useRoute, useRouter } from 'vue-router'
|
|
41
41
|
import { HugeiconsIcon } from '@hugeicons/vue'
|
|
42
42
|
import { Pin02Icon } from '@hugeicons/core-free-icons'
|
|
@@ -45,6 +45,7 @@ import { PinIcon } from '@hugeicons/core-free-icons'
|
|
|
45
45
|
const isOpen = ref(false)
|
|
46
46
|
const isStuck = ref(false)
|
|
47
47
|
const navigationLinks = ref([])
|
|
48
|
+
const sidebarRef = ref(null)
|
|
48
49
|
|
|
49
50
|
const route = useRoute()
|
|
50
51
|
const router = useRouter()
|
|
@@ -206,6 +207,52 @@ function handleLinkClick(callback = null) {
|
|
|
206
207
|
}
|
|
207
208
|
}
|
|
208
209
|
|
|
210
|
+
function handleClickOutside(event) {
|
|
211
|
+
// Only close if sidebar is open and unpinned
|
|
212
|
+
if (!isOpen.value || isStuck.value) {
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const target = event.target
|
|
217
|
+
|
|
218
|
+
// Check if click is on the sidebar toggle button or its container
|
|
219
|
+
// These elements should not trigger the close action
|
|
220
|
+
const sidebarButton = document.getElementById('sidebar-button')
|
|
221
|
+
const sidebarTogglerButton = document.getElementById('sidebar-toggler-button')
|
|
222
|
+
|
|
223
|
+
// Don't close if clicking on toggle button or its parent container
|
|
224
|
+
if (sidebarButton && sidebarButton.contains(target)) {
|
|
225
|
+
return
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (sidebarTogglerButton && sidebarTogglerButton.contains(target)) {
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Check if click is outside the sidebar element
|
|
233
|
+
if (sidebarRef.value && !sidebarRef.value.contains(target)) {
|
|
234
|
+
close()
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Watch for sidebar open/close state to manage event listener
|
|
239
|
+
watch([isOpen, isStuck], ([open, stuck]) => {
|
|
240
|
+
nextTick(() => {
|
|
241
|
+
if (open && !stuck) {
|
|
242
|
+
// Add event listener when sidebar is open and unpinned
|
|
243
|
+
document.addEventListener('click', handleClickOutside)
|
|
244
|
+
} else {
|
|
245
|
+
// Remove event listener when sidebar is closed or pinned
|
|
246
|
+
document.removeEventListener('click', handleClickOutside)
|
|
247
|
+
}
|
|
248
|
+
})
|
|
249
|
+
}, { immediate: true })
|
|
250
|
+
|
|
251
|
+
// Clean up event listener on unmount
|
|
252
|
+
onUnmounted(() => {
|
|
253
|
+
document.removeEventListener('click', handleClickOutside)
|
|
254
|
+
})
|
|
255
|
+
|
|
209
256
|
defineExpose({
|
|
210
257
|
isOpen,
|
|
211
258
|
navigationLinks,
|