Initial commit

This commit is contained in:
2026-04-17 23:26:01 +00:00
commit 2ea4ca5d52
409 changed files with 63459 additions and 0 deletions

43
app/plugins/pocketbase.ts Normal file
View File

@@ -0,0 +1,43 @@
import PocketBase, { LocalAuthStore } from 'pocketbase'
import type { RecordModel } from 'pocketbase'
import type { TypedPocketBase } from '~/types/pocketbase.types'
/**
* Extends LocalAuthStore to make auth state reactive in Vue.
*
* PocketBase mutates its internal state directly on `this`, bypassing any
* reactive() proxy. Instead, `ref` holds a ShallowRef to the store instance,
* and triggerRef() manually notifies Vue after each state change — so consumers
* always read up-to-date values directly from the store without mirroring state.
*/
export class ReactiveAuthStore extends LocalAuthStore {
readonly ref = shallowRef(this)
override save(token: string, record: RecordModel | null) {
super.save(token, record)
triggerRef(this.ref)
}
override clear() {
super.clear()
triggerRef(this.ref)
}
}
export default defineNuxtPlugin((nuxtApp) => {
const pocketbaseUrl = nuxtApp.$config.public.pocketbaseUrl
if (!pocketbaseUrl) {
throw new Error('Pocketbase config not set')
}
const pb = new PocketBase(pocketbaseUrl, new ReactiveAuthStore()) as TypedPocketBase
// Provide pocketbase client to the app
// Will be available eg. as `const { $pb } = useNuxtApp()`
return {
provide: {
pb
}
}
})

View File

@@ -0,0 +1,24 @@
export default defineNuxtPlugin((nuxtApp) => {
/**
* Directive that calls a callback when an element gets visible in the viewport.
*/
nuxtApp.vueApp.directive('on-visible', {
mounted(el, binding) {
const callback = binding.value
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
callback(entry)
observer.disconnect()
}
})
},
{ threshold: 0.5 }
)
observer.observe(el)
}
})
})