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.
@@ -24,8 +24,7 @@ jobs:
24
24
  - name: Setup Node.js
25
25
  uses: actions/setup-node@v4
26
26
  with:
27
- node-version: "lts/*"
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 zero dependency Vue components built on the [FemtoCrank](https://github.com/jamesread/femtocrank) global CSS theme.
5
+ A lightweight set of Vue components built on the [FemtoCrank](https://github.com/jamesread/femtocrank) global CSS theme.
6
6
 
7
7
  [![Maturity Badge](https://img.shields.io/badge/maturity-Production-brightgreen)](#none)
8
8
  [![Discord](https://img.shields.io/discord/846737624960860180?label=Discord%20Server)](https://discord.gg/jhYWWpNJ3v)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "picocrank",
3
- "version": "1.8.8",
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": "^1.2.1",
21
+ "@hugeicons/core-free-icons": "^2.0.0",
22
22
  "@hugeicons/vue": "^1.0.3",
23
- "@vitejs/plugin-vue": "^6.0.1",
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.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
@@ -3,7 +3,7 @@ import vue from '@vitejs/plugin-vue'
3
3
  import Components from 'unplugin-vue-components/vite'
4
4
 
5
5
  export default defineConfig({
6
- base: '/picocrank/',
6
+ base: '/',
7
7
  build: {
8
8
  outDir: 'dist',
9
9
  rollupOptions: {
@@ -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,