chore: lint and fmt
This commit is contained in:
8
.agents/.claude-plugin/plugin.json
Normal file
8
.agents/.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "remanso-skills",
|
||||
"version": "1.0.0",
|
||||
"description": "Local skills for the Remanso project",
|
||||
"author": {
|
||||
"name": "julien"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 80,
|
||||
"sortPackageJson": false,
|
||||
|
||||
@@ -3,28 +3,28 @@
|
||||
// Script pour changer facilement le thème sombre de l'application Remanso
|
||||
// Usage: pnpm run theme:dark [theme-name]
|
||||
|
||||
import { readFileSync, writeFileSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
import { readFileSync, writeFileSync } from "fs"
|
||||
import { join } from "path"
|
||||
|
||||
import { commitTheme } from './change-theme'
|
||||
import { commitTheme } from "./change-theme"
|
||||
|
||||
// Chemins vers les fichiers
|
||||
const themeConfigPath = join(__dirname, '..', 'src', 'theme.config.ts')
|
||||
const appCssPath = join(__dirname, '..', 'src', 'styles', 'app.css')
|
||||
const themeConfigPath = join(__dirname, "..", "src", "theme.config.ts")
|
||||
const appCssPath = join(__dirname, "..", "src", "styles", "app.css")
|
||||
|
||||
// Vérifier les arguments
|
||||
if (process.argv.length < 3) {
|
||||
console.log('Usage: pnpm run theme:dark [theme-name]')
|
||||
console.log('Exemple: pnpm run theme:dark business')
|
||||
console.log("Usage: pnpm run theme:dark [theme-name]")
|
||||
console.log("Exemple: pnpm run theme:dark business")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Mode fixé à dark pour ce script
|
||||
const mode = 'dark'
|
||||
const mode = "dark"
|
||||
const newTheme = process.argv[2] // nom du nouveau thème
|
||||
|
||||
// Lire le contenu actuel du fichier de configuration
|
||||
let themeConfigContent = readFileSync(themeConfigPath, 'utf8')
|
||||
let themeConfigContent = readFileSync(themeConfigPath, "utf8")
|
||||
|
||||
// Remplacer la valeur du thème sombre
|
||||
themeConfigContent = themeConfigContent.replace(
|
||||
@@ -36,7 +36,7 @@ themeConfigContent = themeConfigContent.replace(
|
||||
writeFileSync(themeConfigPath, themeConfigContent)
|
||||
|
||||
// Mettre à jour également le fichier app.css pour le thème --prefersdark
|
||||
let appCssContent = readFileSync(appCssPath, 'utf8')
|
||||
let appCssContent = readFileSync(appCssPath, "utf8")
|
||||
appCssContent = appCssContent.replace(
|
||||
/(\s+)([a-zA-Z0-9-]+)(\s+--prefersdark;)/,
|
||||
`$1${newTheme}$3`
|
||||
|
||||
@@ -3,29 +3,29 @@
|
||||
// Script pour changer facilement le thème clair de l'application Remanso
|
||||
// Usage: pnpm run theme:light [theme-name]
|
||||
|
||||
import { readFileSync, writeFileSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
import { readFileSync, writeFileSync } from "fs"
|
||||
import { join } from "path"
|
||||
|
||||
import { commitTheme } from './change-theme'
|
||||
import { commitTheme } from "./change-theme"
|
||||
|
||||
// Chemins vers les fichiers
|
||||
const themeConfigPath = join(__dirname, '..', 'src', 'theme.config.ts')
|
||||
const indexPath = join(__dirname, '..', 'index.html')
|
||||
const appCssPath = join(__dirname, '..', 'src', 'styles', 'app.css')
|
||||
const themeConfigPath = join(__dirname, "..", "src", "theme.config.ts")
|
||||
const indexPath = join(__dirname, "..", "index.html")
|
||||
const appCssPath = join(__dirname, "..", "src", "styles", "app.css")
|
||||
|
||||
// Vérifier les arguments
|
||||
if (process.argv.length < 3) {
|
||||
console.log('Usage: pnpm run theme:light [theme-name]')
|
||||
console.log('Exemple: pnpm run theme:light cupcake')
|
||||
console.log("Usage: pnpm run theme:light [theme-name]")
|
||||
console.log("Exemple: pnpm run theme:light cupcake")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Mode fixé à light pour ce script
|
||||
const mode = 'light'
|
||||
const mode = "light"
|
||||
const newTheme = process.argv[2] // nom du nouveau thème
|
||||
|
||||
// Lire le contenu actuel du fichier de configuration
|
||||
let themeConfigContent = readFileSync(themeConfigPath, 'utf8')
|
||||
let themeConfigContent = readFileSync(themeConfigPath, "utf8")
|
||||
|
||||
// Remplacer la valeur du thème clair
|
||||
themeConfigContent = themeConfigContent.replace(
|
||||
@@ -37,7 +37,7 @@ themeConfigContent = themeConfigContent.replace(
|
||||
writeFileSync(themeConfigPath, themeConfigContent)
|
||||
|
||||
// Mettre à jour également le fichier index.html
|
||||
let indexContent = readFileSync(indexPath, 'utf8')
|
||||
let indexContent = readFileSync(indexPath, "utf8")
|
||||
indexContent = indexContent.replace(
|
||||
/data-theme="[^"]*"/,
|
||||
`data-theme="${newTheme}"`
|
||||
@@ -45,7 +45,7 @@ indexContent = indexContent.replace(
|
||||
writeFileSync(indexPath, indexContent)
|
||||
|
||||
// Mettre à jour également le fichier app.css pour le thème --default
|
||||
let appCssContent = readFileSync(appCssPath, 'utf8')
|
||||
let appCssContent = readFileSync(appCssPath, "utf8")
|
||||
appCssContent = appCssContent.replace(
|
||||
/(\s+)([a-zA-Z0-9-]+)(\s+--default,)/,
|
||||
`$1${newTheme}$3`
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { execSync } from 'child_process'
|
||||
import { execSync } from "child_process"
|
||||
|
||||
export const commitTheme = (mode: string, newTheme: string) => {
|
||||
// Créer un commit avec les changements
|
||||
try {
|
||||
// Ajouter tous les fichiers modifiés
|
||||
execSync('git add .', { stdio: 'inherit' })
|
||||
execSync("git add .", { stdio: "inherit" })
|
||||
|
||||
// Créer le commit avec le message approprié
|
||||
const commitMessage = `design: change ${mode} theme to ${newTheme}`
|
||||
execSync(`git commit -m "${commitMessage}"`, { stdio: 'inherit' })
|
||||
execSync(`git commit -m "${commitMessage}"`, { stdio: "inherit" })
|
||||
|
||||
console.log(`Commit créé avec succès: "${commitMessage}"`)
|
||||
|
||||
execSync(`git push`, { stdio: 'inherit' })
|
||||
execSync(`git push`, { stdio: "inherit" })
|
||||
|
||||
console.log(`Push sur origin`)
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création du commit:', error)
|
||||
console.error("Erreur lors de la création du commit:", error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module.exports = {
|
||||
presets: ['@vue/cli-plugin-babel/preset']
|
||||
presets: ["@vue/cli-plugin-babel/preset"]
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ Rolldown's minifier drops the `while(`/`for(;` keyword when a `while (x in globa
|
||||
File: `node_modules/@ark/schema/out/shared/registry.js`
|
||||
|
||||
```js
|
||||
let _registryName = '$ark'
|
||||
let _registryName = "$ark"
|
||||
let suffix = 2
|
||||
while (_registryName in globalThis) _registryName = `$ark${suffix++}`
|
||||
export const registryName = _registryName
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module.exports = {
|
||||
plugins: { '@tailwindcss/postcss': {}, autoprefixer: {} }
|
||||
plugins: { "@tailwindcss/postcss": {}, autoprefixer: {} }
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {
|
||||
defineConfig,
|
||||
minimal2023Preset as preset
|
||||
} from '@vite-pwa/assets-generator/config'
|
||||
} from "@vite-pwa/assets-generator/config"
|
||||
|
||||
export default defineConfig({
|
||||
preset,
|
||||
images: ['public/favicon.png']
|
||||
images: ["public/favicon.png"]
|
||||
})
|
||||
|
||||
@@ -5,5 +5,5 @@ export const op = new OpenPanel({
|
||||
clientId: "038a6aac-19bb-4a7f-9aae-2d0201fead5b",
|
||||
trackScreenViews: true,
|
||||
trackOutgoingLinks: true,
|
||||
trackAttributes: true,
|
||||
trackAttributes: true
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createEventBus } from 'retrobus'
|
||||
import { createEventBus } from "retrobus"
|
||||
|
||||
interface EventBusParams {
|
||||
fileSha: string
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createEventBus } from 'retrobus'
|
||||
import { createEventBus } from "retrobus"
|
||||
|
||||
interface EventBusParams {
|
||||
user: string
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
import { onBeforeMount, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { onBeforeMount, ref } from "vue"
|
||||
import { useRoute, useRouter } from "vue-router"
|
||||
|
||||
import { useGitHubLogin } from '@/hooks/useGitHubLogin.hook'
|
||||
import { signIn } from '@/modules/user/service/signIn'
|
||||
import { useGitHubLogin } from "@/hooks/useGitHubLogin.hook"
|
||||
import { signIn } from "@/modules/user/service/signIn"
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@@ -16,14 +16,14 @@ onBeforeMount(async () => {
|
||||
if (code) {
|
||||
const token = await signIn(code.toString())
|
||||
|
||||
if ('error' in token) {
|
||||
if ("error" in token) {
|
||||
hasError.value = true
|
||||
} else {
|
||||
token.access_token
|
||||
saveCredentials(token)
|
||||
}
|
||||
|
||||
router.replace({ name: 'Home' })
|
||||
router.replace({ name: "Home" })
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter, type RouteLocationRaw } from "vue-router"
|
||||
import { type RouteLocationRaw, useRouter } from "vue-router"
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{ fallback?: RouteLocationRaw; preferFallback?: boolean }>(),
|
||||
{ preferFallback: true },
|
||||
{ preferFallback: true }
|
||||
)
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@@ -6,9 +6,10 @@ import {
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
toRefs,
|
||||
watch,
|
||||
watch
|
||||
} from "vue"
|
||||
|
||||
import SkeletonLoader from "@/components/SkeletonLoader.vue"
|
||||
import StackedNote from "@/components/StackedNote.vue"
|
||||
import { useLinks } from "@/hooks/useLinks.hook"
|
||||
import { markdownBuilder } from "@/hooks/useMarkdown.hook"
|
||||
@@ -19,10 +20,9 @@ import { useVisitRepo } from "@/modules/history/hooks/useVisitRepo.hook"
|
||||
import CacheAllNotes from "@/modules/note/components/CacheAllNote.vue"
|
||||
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
|
||||
import { useUserSettings } from "@/modules/user/hooks/useUserSettings.hook"
|
||||
import SkeletonLoader from "@/components/SkeletonLoader.vue"
|
||||
|
||||
const HeaderNote = defineAsyncComponent(
|
||||
() => import("@/components/HeaderNote.vue"),
|
||||
() => import("@/components/HeaderNote.vue")
|
||||
)
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -38,8 +38,8 @@ const props = withDefaults(
|
||||
content: null,
|
||||
parseContent: true,
|
||||
withContent: true,
|
||||
withHeader: true,
|
||||
},
|
||||
withHeader: true
|
||||
}
|
||||
)
|
||||
|
||||
const user = computed(() => props.user)
|
||||
@@ -61,7 +61,7 @@ const renderedContent = computed(() =>
|
||||
? props.parseContent
|
||||
? toHTML(props.content)
|
||||
: props.content
|
||||
: store.readme,
|
||||
: store.readme
|
||||
)
|
||||
|
||||
const isLoading = computed(() => renderedContent.value === undefined)
|
||||
@@ -73,7 +73,7 @@ watch(
|
||||
await nextTick()
|
||||
listenToClick()
|
||||
},
|
||||
{ immediate: true },
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
@@ -81,7 +81,7 @@ watch(
|
||||
() => {
|
||||
store.setUserRepo(props.user, props.repo)
|
||||
},
|
||||
{ immediate: true },
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
onMounted(() => visitRepo())
|
||||
|
||||
@@ -9,7 +9,7 @@ const store = useUserRepoStore()
|
||||
|
||||
const fontFamilies = computed(() => store.userSettings?.fontFamilies ?? [])
|
||||
const sortedFontFamilies = computed(() =>
|
||||
[...fontFamilies.value].sort((a, b) => a.localeCompare(b)),
|
||||
[...fontFamilies.value].sort((a, b) => a.localeCompare(b))
|
||||
)
|
||||
const fontSizes = Array.from({ length: 7 }, (_, i) => `${9 + i * 2}pt`)
|
||||
</script>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script lang="ts" setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useRouter } from "vue-router"
|
||||
|
||||
const { push } = useRouter()
|
||||
|
||||
const back = () =>
|
||||
push({
|
||||
name: 'Home'
|
||||
name: "Home"
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
const url = new URL('https://github.com/login/oauth/authorize')
|
||||
url.searchParams.append('client_id', 'Iv1.87be14adcc912fa0')
|
||||
url.searchParams.append('redirect_uri', location.href)
|
||||
url.searchParams.append('scope', 'repo')
|
||||
const url = new URL("https://github.com/login/oauth/authorize")
|
||||
url.searchParams.append("client_id", "Iv1.87be14adcc912fa0")
|
||||
url.searchParams.append("redirect_uri", location.href)
|
||||
url.searchParams.append("scope", "repo")
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { PublicNoteListItem } from "@/modules/note/models/Note"
|
||||
import { toShortDid } from "@/modules/atproto/shortDid"
|
||||
import { slugify } from "@/utils/slugify"
|
||||
import { vInfiniteScroll } from "@vueuse/components"
|
||||
|
||||
import { toShortDid } from "@/modules/atproto/shortDid"
|
||||
import { PublicNoteListItem } from "@/modules/note/models/Note"
|
||||
import { slugify } from "@/utils/slugify"
|
||||
|
||||
defineProps<{
|
||||
notes: PublicNoteListItem[]
|
||||
canLoadMore: boolean
|
||||
@@ -28,8 +29,8 @@ defineSlots<{
|
||||
params: {
|
||||
shortDid: toShortDid(note.did),
|
||||
rkey: note.rkey,
|
||||
slug: slugify(note.title),
|
||||
},
|
||||
slug: slugify(note.title)
|
||||
}
|
||||
}"
|
||||
class="btn btn-link"
|
||||
>{{ note.title }}</router-link
|
||||
|
||||
@@ -26,8 +26,8 @@ const getStyle = (seed: string) => {
|
||||
name: 'FluxNoteView',
|
||||
params: {
|
||||
user: username,
|
||||
repo: favoriteRepo.name,
|
||||
},
|
||||
repo: favoriteRepo.name
|
||||
}
|
||||
}"
|
||||
class="btn"
|
||||
:style="getStyle(`${favoriteRepo.name}-${username}`)"
|
||||
|
||||
@@ -3,15 +3,16 @@ import { ref } from "vue"
|
||||
|
||||
import { useATProtoLogin } from "@/hooks/useATProtoLogin.hook"
|
||||
|
||||
const { handle, isLoggedIn, isATProtoReady, signIn, signOut } = useATProtoLogin()
|
||||
const { handle, isLoggedIn, isATProtoReady, signIn, signOut } =
|
||||
useATProtoLogin()
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
withSignOut?: boolean
|
||||
}>(),
|
||||
{
|
||||
withSignOut: true,
|
||||
},
|
||||
withSignOut: true
|
||||
}
|
||||
)
|
||||
|
||||
const inputHandle = ref("")
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
nextTick,
|
||||
onMounted,
|
||||
ref,
|
||||
watch,
|
||||
watch
|
||||
} from "vue"
|
||||
|
||||
import { useEditionMode } from "@/hooks/useEditionMode"
|
||||
@@ -13,20 +13,20 @@ import { useFile } from "@/hooks/useFile.hook"
|
||||
import { useGitHubContent } from "@/hooks/useGitHubContent.hook"
|
||||
import { useImages } from "@/hooks/useImages.hook"
|
||||
import { useLinks } from "@/hooks/useLinks.hook"
|
||||
import { runMermaid, useShikiji } from "@/hooks/useMarkdown.hook"
|
||||
import { useNoteOverlay } from "@/hooks/useNoteOverlay.hook"
|
||||
import { useRouteQueryStackedNotes } from "@/hooks/useRouteQueryStackedNotes.hook"
|
||||
import { useTitleNotes } from "@/hooks/useTitleNotes.hook"
|
||||
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
|
||||
import { encodeUTF8ToBase64 } from "@/utils/decodeBase64ToUTF8"
|
||||
import { filenameToNoteTitle } from "@/utils/noteTitle"
|
||||
import { runMermaid, useShikiji } from "@/hooks/useMarkdown.hook"
|
||||
|
||||
const LinkedNotes = defineAsyncComponent(
|
||||
() => import("@/components/LinkedNotes.vue"),
|
||||
() => import("@/components/LinkedNotes.vue")
|
||||
)
|
||||
|
||||
const EditNote = defineAsyncComponent(
|
||||
() => import("@/modules/note/components/EditNote.vue"),
|
||||
() => import("@/modules/note/components/EditNote.vue")
|
||||
)
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -50,7 +50,7 @@ const {
|
||||
rawContent,
|
||||
getRawContent,
|
||||
saveCacheNote,
|
||||
getEditedSha,
|
||||
getEditedSha
|
||||
} = useFile(sha)
|
||||
const initialRawContent = ref<string | null>(null)
|
||||
const className = computed(() => `stacked-note-${props.index}`)
|
||||
@@ -67,7 +67,7 @@ const breadcrumbs = computed(() => displayedTitle.value.split(" / "))
|
||||
|
||||
const { updateFile } = useGitHubContent({
|
||||
user: user.value,
|
||||
repo: repo.value,
|
||||
repo: repo.value
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -115,7 +115,7 @@ watch(mode, async (newMode) => {
|
||||
const newSha = await updateFile({
|
||||
content: rawContent.value,
|
||||
path: path.value,
|
||||
sha: editedSha,
|
||||
sha: editedSha
|
||||
})
|
||||
|
||||
if (!newSha) {
|
||||
@@ -125,7 +125,7 @@ watch(mode, async (newMode) => {
|
||||
}
|
||||
|
||||
await saveCacheNote(encodeUTF8ToBase64(rawContent.value), {
|
||||
editedSha: newSha,
|
||||
editedSha: newSha
|
||||
})
|
||||
initialRawContent.value = rawContent.value
|
||||
})
|
||||
@@ -137,7 +137,7 @@ watch(mode, async (newMode) => {
|
||||
:class="{
|
||||
[className]: true,
|
||||
overlay: displayNoteOverlay,
|
||||
[`note-${sha}`]: true,
|
||||
[`note-${sha}`]: true
|
||||
}"
|
||||
>
|
||||
<a
|
||||
@@ -198,7 +198,9 @@ watch(mode, async (newMode) => {
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M6 4h10l4 4v10a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2" />
|
||||
<path
|
||||
d="M6 4h10l4 4v10a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2"
|
||||
/>
|
||||
<path d="M12 14m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
|
||||
<path d="M14 4l0 4l-6 0l0 -4" />
|
||||
</svg>
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
<script lang="ts" setup>
|
||||
import { computedAsync } from "@vueuse/core"
|
||||
import { computed, nextTick, ref, watch } from "vue"
|
||||
import { useRoute } from "vue-router"
|
||||
import { errorMessage } from "@/utils/notif"
|
||||
|
||||
import SkeletonLoader from "@/components/SkeletonLoader.vue"
|
||||
import { useATProtoLinks } from "@/hooks/useATProtoLinks.hook"
|
||||
import { markdownBuilder } from "@/hooks/useMarkdown.hook"
|
||||
import { useNoteOverlay } from "@/hooks/useNoteOverlay.hook"
|
||||
import { useRouteQueryStackedNotes } from "@/hooks/useRouteQueryStackedNotes.hook"
|
||||
import { markdownBuilder } from "@/hooks/useMarkdown.hook"
|
||||
import { computedAsync } from "@vueuse/core"
|
||||
import { getUrl } from "@/modules/atproto/getUrl"
|
||||
import { withATProtoImages } from "@/modules/atproto/withATProtoImages"
|
||||
import { getAuthor } from "@/modules/atproto/getAuthor"
|
||||
import { fromShortDid } from "@/modules/atproto/shortDid"
|
||||
import { getUrl } from "@/modules/atproto/getUrl"
|
||||
import { PublicNoteRecord } from "@/modules/atproto/publicNote.types"
|
||||
import SkeletonLoader from "@/components/SkeletonLoader.vue"
|
||||
import { fromShortDid } from "@/modules/atproto/shortDid"
|
||||
import { withATProtoImages } from "@/modules/atproto/withATProtoImages"
|
||||
import { errorMessage } from "@/utils/notif"
|
||||
|
||||
const props = defineProps<{
|
||||
didrkey: string
|
||||
@@ -28,7 +29,7 @@ const index = computed(() => props.index)
|
||||
|
||||
const author = computedAsync(async () => getAuthor(did.value))
|
||||
const url = computedAsync(async () =>
|
||||
getUrl({ did: did.value, rkey: rkey.value }),
|
||||
getUrl({ did: did.value, rkey: rkey.value })
|
||||
)
|
||||
|
||||
const className = computed(() => `stacked-note-${props.index}`)
|
||||
@@ -36,13 +37,13 @@ const titleClassName = computed(() => `title-${className.value}`)
|
||||
|
||||
const route = useRoute()
|
||||
const mainNoteId = computed(
|
||||
() => `${route.params.shortDid}-${route.params.rkey}`,
|
||||
() => `${route.params.shortDid}-${route.params.rkey}`
|
||||
)
|
||||
|
||||
const { scrollToFocusedNote } = useRouteQueryStackedNotes()
|
||||
const { listenToClick } = useATProtoLinks(className.value, {
|
||||
currentAtUri: didrkey,
|
||||
mainNoteId,
|
||||
mainNoteId
|
||||
})
|
||||
const { displayNoteOverlay } = useNoteOverlay(className.value, index)
|
||||
|
||||
@@ -69,10 +70,10 @@ const content = computed(() =>
|
||||
? toHTML(
|
||||
withATProtoImages(noteRecord.value.value.content, {
|
||||
pds: author.value.pds,
|
||||
did: did.value,
|
||||
}),
|
||||
did: did.value
|
||||
})
|
||||
)
|
||||
: "",
|
||||
: ""
|
||||
)
|
||||
|
||||
watch(
|
||||
@@ -81,7 +82,7 @@ watch(
|
||||
await nextTick()
|
||||
listenToClick()
|
||||
},
|
||||
{ immediate: true },
|
||||
{ immediate: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -91,7 +92,7 @@ watch(
|
||||
:class="{
|
||||
[className]: true,
|
||||
overlay: displayNoteOverlay,
|
||||
[`note-${classNameId}`]: true,
|
||||
[`note-${classNameId}`]: true
|
||||
}"
|
||||
>
|
||||
<a
|
||||
|
||||
@@ -77,7 +77,7 @@ const { userInput, repoInput, submit } = useForm()
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'FluxNoteView',
|
||||
params: { user: 'remanso-space', repo: 'getting-started' },
|
||||
params: { user: 'remanso-space', repo: 'getting-started' }
|
||||
}"
|
||||
class="btn btn-sm"
|
||||
>Get started</router-link
|
||||
|
||||
@@ -4,8 +4,8 @@ export const getNoteWidth = () => {
|
||||
if (cached === undefined) {
|
||||
cached = parseInt(
|
||||
getComputedStyle(document.documentElement).getPropertyValue(
|
||||
"--note-width",
|
||||
),
|
||||
"--note-width"
|
||||
)
|
||||
)
|
||||
}
|
||||
return cached
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export enum DataType {
|
||||
GithubAccessToken = 'GithubAccessToken',
|
||||
FavoriteRepo = 'FavoriteRepo',
|
||||
SavedRepo = 'SavedRepo',
|
||||
Note = 'Note',
|
||||
BacklinkNote = 'BacklinkNote',
|
||||
RepetitionCard = 'RepetitionCard',
|
||||
History = 'History',
|
||||
UserSettings = 'UserSettings',
|
||||
AtprotoSession = 'AtprotoSession'
|
||||
GithubAccessToken = "GithubAccessToken",
|
||||
FavoriteRepo = "FavoriteRepo",
|
||||
SavedRepo = "SavedRepo",
|
||||
Note = "Note",
|
||||
BacklinkNote = "BacklinkNote",
|
||||
RepetitionCard = "RepetitionCard",
|
||||
History = "History",
|
||||
UserSettings = "UserSettings",
|
||||
AtprotoSession = "AtprotoSession"
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class Data {
|
||||
constructor() {
|
||||
try {
|
||||
this.locale = new PouchDb("remanso", {
|
||||
adapter: "indexeddb",
|
||||
adapter: "indexeddb"
|
||||
})
|
||||
} catch (error) {
|
||||
console.warn("data error", error)
|
||||
@@ -40,7 +40,7 @@ class Data {
|
||||
}
|
||||
|
||||
public async update<DT extends DataType, T extends Model<DT>>(
|
||||
model: T,
|
||||
model: T
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
if (!model._id) {
|
||||
@@ -71,7 +71,7 @@ class Data {
|
||||
}
|
||||
const result = await this.locale?.put({
|
||||
...doc,
|
||||
_deleted: true,
|
||||
_deleted: true
|
||||
})
|
||||
return result?.ok ?? false
|
||||
} catch {
|
||||
@@ -80,7 +80,7 @@ class Data {
|
||||
}
|
||||
|
||||
public async get<DT extends DataType, T extends Model<DT>>(
|
||||
id: string,
|
||||
id: string
|
||||
): Promise<T | null> {
|
||||
try {
|
||||
return ((await this.locale?.get(id)) as T) || null
|
||||
@@ -91,7 +91,7 @@ class Data {
|
||||
|
||||
public async getOrCreate<DT extends DataType, T extends Model<DT>>(
|
||||
id: string,
|
||||
initialValue: T,
|
||||
initialValue: T
|
||||
): Promise<T> {
|
||||
const element = await this.get<DT, T>(id)
|
||||
|
||||
@@ -108,7 +108,7 @@ class Data {
|
||||
prefix,
|
||||
includeDocs = true,
|
||||
includeAttachments = false,
|
||||
keys = [],
|
||||
keys = []
|
||||
}: GetAllParams): Promise<T[]> {
|
||||
if (!this.locale) {
|
||||
return []
|
||||
@@ -118,7 +118,7 @@ class Data {
|
||||
const response = await this.locale.allDocs({
|
||||
include_docs: includeDocs,
|
||||
attachments: includeAttachments,
|
||||
keys: keys.map((key) => this.generateId(prefix, key)),
|
||||
keys: keys.map((key) => this.generateId(prefix, key))
|
||||
})
|
||||
|
||||
if (includeDocs) {
|
||||
@@ -148,7 +148,7 @@ class Data {
|
||||
include_docs: includeDocs,
|
||||
attachments: includeAttachments,
|
||||
startkey: prefix ? prefix : undefined,
|
||||
endkey: prefix ? `${prefix}\ufff0` : undefined,
|
||||
endkey: prefix ? `${prefix}\ufff0` : undefined
|
||||
})
|
||||
|
||||
return response.rows.map((row) => row.doc) as T[]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { Model } from '@/data/models/Model'
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { Model } from "@/data/models/Model"
|
||||
|
||||
export interface AtprotoSession extends Model<DataType.AtprotoSession> {
|
||||
did: string
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { Model } from '@/data/models/Model'
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { Model } from "@/data/models/Model"
|
||||
|
||||
export interface GithubAccessToken extends Model<DataType.GithubAccessToken> {
|
||||
username: string
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { Model } from '@/data/models/Model'
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { Model } from "@/data/models/Model"
|
||||
|
||||
export interface History extends Model<DataType.History> {
|
||||
repos: ReadonlyArray<{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DataType } from '../DataType.enum'
|
||||
import { DataType } from "../DataType.enum"
|
||||
|
||||
export interface Model<DT extends DataType> {
|
||||
_id?: string
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { ComputedRef, onUnmounted, Ref, toValue } from "vue"
|
||||
|
||||
import { isExternalLink } from "@/utils/link"
|
||||
import { useRouteQueryStackedNotes } from "@/hooks/useRouteQueryStackedNotes.hook"
|
||||
import { parseAtUri } from "@/modules/atproto/parseAtUri"
|
||||
import { toShortDid } from "@/modules/atproto/shortDid"
|
||||
import { router } from "@/router/router"
|
||||
import { isExternalLink } from "@/utils/link"
|
||||
|
||||
export const useATProtoLinks = (
|
||||
className: ComputedRef<string> | string,
|
||||
options: {
|
||||
currentAtUri?: Ref<string> | string | ComputedRef<string>
|
||||
mainNoteId: Ref<string> | string | ComputedRef<string>
|
||||
},
|
||||
}
|
||||
) => {
|
||||
const { addStackedNote, scrollToFocusedNote } = useRouteQueryStackedNotes()
|
||||
const { currentAtUri, mainNoteId } = options
|
||||
@@ -38,7 +38,7 @@ export const useATProtoLinks = (
|
||||
|
||||
if (href.startsWith(window.location.origin)) {
|
||||
const { params } = router.resolve(
|
||||
href.replace(window.location.origin, ""),
|
||||
href.replace(window.location.origin, "")
|
||||
)
|
||||
|
||||
if (!params.shortDid || !params.rkey) {
|
||||
@@ -57,7 +57,7 @@ export const useATProtoLinks = (
|
||||
addStackedNote(
|
||||
toValue(currentAtUri) ?? "",
|
||||
noteId,
|
||||
`${params.shortDid}-${params.rkey}`,
|
||||
`${params.shortDid}-${params.rkey}`
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -111,6 +111,6 @@ export const useATProtoLinks = (
|
||||
})
|
||||
|
||||
return {
|
||||
listenToClick,
|
||||
listenToClick
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, ref } from "vue"
|
||||
|
||||
import { getAuthor } from '@/modules/atproto/getAuthor'
|
||||
import { restoreSession, sdkSignOut, signInWithHandle } from '@/modules/atproto/service/atprotoOAuth'
|
||||
import { clearSession, loadSession, saveSession } from '@/modules/atproto/service/atprotoSession'
|
||||
import { getAuthor } from "@/modules/atproto/getAuthor"
|
||||
import {
|
||||
restoreSession,
|
||||
sdkSignOut,
|
||||
signInWithHandle
|
||||
} from "@/modules/atproto/service/atprotoOAuth"
|
||||
import {
|
||||
clearSession,
|
||||
loadSession,
|
||||
saveSession
|
||||
} from "@/modules/atproto/service/atprotoSession"
|
||||
|
||||
const did = ref<string | null>(null)
|
||||
const handle = ref<string | null>(null)
|
||||
@@ -12,20 +20,24 @@ let init = true
|
||||
const initializeAuth = async () => {
|
||||
// Load cached session from IndexedDB first (fast, local) so the UI can render immediately
|
||||
const stored = await loadSession()
|
||||
did.value = stored?.did ?? ''
|
||||
handle.value = stored?.handle ?? ''
|
||||
did.value = stored?.did ?? ""
|
||||
handle.value = stored?.handle ?? ""
|
||||
|
||||
// Then restore OAuth session in the background (may involve network)
|
||||
const session = await restoreSession()
|
||||
if (session) {
|
||||
const author = await getAuthor(session.did)
|
||||
const resolvedHandle = author?.handle ?? ''
|
||||
const resolvedHandle = author?.handle ?? ""
|
||||
|
||||
did.value = session.did
|
||||
handle.value = resolvedHandle
|
||||
await saveSession(session.did, resolvedHandle)
|
||||
|
||||
window.history.replaceState(null, '', window.location.pathname + window.location.search)
|
||||
window.history.replaceState(
|
||||
null,
|
||||
"",
|
||||
window.location.pathname + window.location.search
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +59,8 @@ export const useATProtoLogin = () => {
|
||||
await sdkSignOut(did.value)
|
||||
}
|
||||
await clearSession()
|
||||
did.value = ''
|
||||
handle.value = ''
|
||||
did.value = ""
|
||||
handle.value = ""
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -57,6 +69,6 @@ export const useATProtoLogin = () => {
|
||||
isLoggedIn,
|
||||
isATProtoReady,
|
||||
signIn,
|
||||
signOut,
|
||||
signOut
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useAsyncState } from '@vueuse/core'
|
||||
import { ComputedRef, onUnmounted, toValue } from 'vue'
|
||||
import { useAsyncState } from "@vueuse/core"
|
||||
import { ComputedRef, onUnmounted, toValue } from "vue"
|
||||
|
||||
import { backlinkEventBus } from '@/bus/backlinkEventBus'
|
||||
import { data } from '@/data/data'
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { BacklinkNote } from '@/modules/note/models/BacklinkNote'
|
||||
import { backlinkEventBus } from "@/bus/backlinkEventBus"
|
||||
import { data } from "@/data/data"
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { BacklinkNote } from "@/modules/note/models/BacklinkNote"
|
||||
|
||||
export const useBacklinks = (sha: string | ComputedRef<string>) => {
|
||||
sha = toValue(sha)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ref, Ref, toValue, onUnmounted } from "vue"
|
||||
import { useDebounceFn } from "@vueuse/core"
|
||||
import { onUnmounted, Ref, ref, toValue } from "vue"
|
||||
|
||||
import { useGitHubContent } from "@/hooks/useGitHubContent.hook"
|
||||
|
||||
const CHECKBOX_PATTERN = /\[([ xX])\]/g
|
||||
@@ -7,7 +8,7 @@ const CHECKBOX_PATTERN = /\[([ xX])\]/g
|
||||
const setCheckboxInMarkdown = (
|
||||
markdown: string,
|
||||
index: number,
|
||||
checked: boolean,
|
||||
checked: boolean
|
||||
): string => {
|
||||
let currentIndex = 0
|
||||
|
||||
@@ -21,7 +22,7 @@ const setCheckboxInMarkdown = (
|
||||
|
||||
const findCheckboxIndex = (
|
||||
container: Element,
|
||||
checkbox: HTMLInputElement,
|
||||
checkbox: HTMLInputElement
|
||||
): number => {
|
||||
const allCheckboxes = container.querySelectorAll('input[type="checkbox"]')
|
||||
return Array.from(allCheckboxes).indexOf(checkbox)
|
||||
@@ -34,7 +35,7 @@ export const useCheckboxCommit = ({
|
||||
initialContent,
|
||||
initialSha,
|
||||
containerSelector,
|
||||
debounceMs = 1000,
|
||||
debounceMs = 1000
|
||||
}: {
|
||||
user: string
|
||||
repo: string
|
||||
@@ -76,7 +77,7 @@ export const useCheckboxCommit = ({
|
||||
const newSha = await updateFile({
|
||||
content: pendingContent.value,
|
||||
path: pathValue,
|
||||
sha: currentSha.value,
|
||||
sha: currentSha.value
|
||||
})
|
||||
|
||||
if (newSha) {
|
||||
@@ -109,7 +110,7 @@ export const useCheckboxCommit = ({
|
||||
pendingContent.value = setCheckboxInMarkdown(
|
||||
pendingContent.value,
|
||||
index,
|
||||
target.checked,
|
||||
target.checked
|
||||
)
|
||||
hasPendingChanges.value = true
|
||||
|
||||
@@ -142,6 +143,6 @@ export const useCheckboxCommit = ({
|
||||
isCommitting,
|
||||
hasPendingChanges,
|
||||
syncContent,
|
||||
listenToCheckboxes,
|
||||
listenToCheckboxes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { watch } from 'vue'
|
||||
import { watch } from "vue"
|
||||
|
||||
import { backlinkEventBus } from '@/bus/backlinkEventBus'
|
||||
import { data } from '@/data/data'
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { useFile } from '@/hooks/useFile.hook'
|
||||
import { Backlink } from '@/modules/note/models/Backlink'
|
||||
import { BacklinkNote } from '@/modules/note/models/BacklinkNote'
|
||||
import { resolvePath } from '@/modules/repo/services/resolvePath'
|
||||
import { useUserRepoStore } from '@/modules/repo/store/userRepo.store'
|
||||
import { isExternalLink } from '@/utils/link'
|
||||
import { filenameToNoteTitle } from '@/utils/noteTitle'
|
||||
import { confirmMessage } from '@/utils/notif'
|
||||
import { backlinkEventBus } from "@/bus/backlinkEventBus"
|
||||
import { data } from "@/data/data"
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { useFile } from "@/hooks/useFile.hook"
|
||||
import { Backlink } from "@/modules/note/models/Backlink"
|
||||
import { BacklinkNote } from "@/modules/note/models/BacklinkNote"
|
||||
import { resolvePath } from "@/modules/repo/services/resolvePath"
|
||||
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
|
||||
import { isExternalLink } from "@/utils/link"
|
||||
import { filenameToNoteTitle } from "@/utils/noteTitle"
|
||||
import { confirmMessage } from "@/utils/notif"
|
||||
|
||||
const isMarkdown = (filename?: string) => filename?.endsWith('.md') ?? false
|
||||
const isMarkdown = (filename?: string) => filename?.endsWith(".md") ?? false
|
||||
|
||||
export const useComputeBacklinks = () => {
|
||||
const store = useUserRepoStore()
|
||||
@@ -51,18 +51,18 @@ export const useComputeBacklinks = () => {
|
||||
}
|
||||
|
||||
const parser = new DOMParser()
|
||||
const htmlDoc = parser.parseFromString(note, 'text/html')
|
||||
const htmlDoc = parser.parseFromString(note, "text/html")
|
||||
|
||||
const links = htmlDoc.querySelectorAll('a')
|
||||
const links = htmlDoc.querySelectorAll("a")
|
||||
|
||||
for (const link of links) {
|
||||
const href = link.getAttribute('href') ?? ''
|
||||
const href = link.getAttribute("href") ?? ""
|
||||
|
||||
if (isExternalLink(href) || !isMarkdown(href)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const path = resolvePath(file.path ?? '', href)
|
||||
const path = resolvePath(file.path ?? "", href)
|
||||
const backlinkFile = store.files.find((file) => file.path === path)
|
||||
|
||||
if (!backlinkFile?.sha || !backlinkFile?.path) {
|
||||
@@ -77,14 +77,14 @@ export const useComputeBacklinks = () => {
|
||||
|
||||
if (!notifiedForComputation) {
|
||||
notifiedForComputation = true
|
||||
confirmMessage('Updating backlinks...')
|
||||
confirmMessage("Updating backlinks...")
|
||||
}
|
||||
|
||||
backlinks.set(backlinkFile.sha, [
|
||||
...previousBacklinks,
|
||||
{
|
||||
sha: file.sha,
|
||||
title: filenameToNoteTitle(file.path ?? '')
|
||||
title: filenameToNoteTitle(file.path ?? "")
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { useMagicKeys } from '@vueuse/core'
|
||||
import { ref, watch } from 'vue'
|
||||
import { useMagicKeys } from "@vueuse/core"
|
||||
import { ref, watch } from "vue"
|
||||
|
||||
export const useEditionMode = () => {
|
||||
const mode = ref<'read' | 'edit'>('read')
|
||||
const mode = ref<"read" | "edit">("read")
|
||||
const toggleMode = () => {
|
||||
mode.value = mode.value === 'read' ? 'edit' : 'read'
|
||||
mode.value = mode.value === "read" ? "edit" : "read"
|
||||
}
|
||||
|
||||
const { escape } = useMagicKeys()
|
||||
|
||||
watch(escape, () => {
|
||||
if (mode.value === 'edit') {
|
||||
if (mode.value === "edit") {
|
||||
toggleMode()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -17,18 +17,18 @@ export const useFile = (sha: Ref<string> | string, retrieveContent = true) => {
|
||||
const {
|
||||
render,
|
||||
renderFromUTF8,
|
||||
getRawContent: getRawContentFromFile,
|
||||
getRawContent: getRawContentFromFile
|
||||
} = markdownBuilder(shaValue)
|
||||
|
||||
const { getCachedNote, saveCacheNote } = prepareNoteCache(
|
||||
shaValue,
|
||||
toValue(path),
|
||||
toValue(path)
|
||||
)
|
||||
|
||||
const fromCache = ref(false)
|
||||
const rawContent = ref("")
|
||||
const content = computed(() =>
|
||||
rawContent.value ? renderFromUTF8(rawContent.value) : "",
|
||||
rawContent.value ? renderFromUTF8(rawContent.value) : ""
|
||||
)
|
||||
|
||||
const getEditedSha = async () => {
|
||||
@@ -55,7 +55,7 @@ export const useFile = (sha: Ref<string> | string, retrieveContent = true) => {
|
||||
}
|
||||
saveCacheNote(fileContent)
|
||||
rawContent.value = getRawContentFromFile(fileContent)
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -111,6 +111,6 @@ export const useFile = (sha: Ref<string> | string, retrieveContent = true) => {
|
||||
getCachedFileContent,
|
||||
getEditedSha,
|
||||
fromCache,
|
||||
saveCacheNote,
|
||||
saveCacheNote
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import { computedAsync } from "@vueuse/core"
|
||||
import { computed, Ref, ref, watch } from "vue"
|
||||
|
||||
import { Author, getAuthors } from "@/modules/atproto/getAuthor"
|
||||
import { PublicNoteListItem } from "@/modules/note/models/Note"
|
||||
import { computedAsync } from "@vueuse/core"
|
||||
import { computed, ref, Ref, watch } from "vue"
|
||||
|
||||
export function useFollowingNoteList(
|
||||
dids: Ref<Set<string>>,
|
||||
enabled: Ref<boolean>,
|
||||
enabled: Ref<boolean>
|
||||
) {
|
||||
const isLoading = ref(false)
|
||||
const notes = ref<PublicNoteListItem[]>([])
|
||||
const cursor = ref<string | null | undefined>(null)
|
||||
const canLoadMore = computed(
|
||||
() => dids.value.size > 0 && cursor.value !== undefined,
|
||||
() => dids.value.size > 0 && cursor.value !== undefined
|
||||
)
|
||||
|
||||
const onLoadMore = async () => {
|
||||
@@ -22,7 +23,7 @@ export function useFollowingNoteList(
|
||||
|
||||
const body: { dids: string[]; limit: number; cursor?: string } = {
|
||||
dids: [...dids.value],
|
||||
limit: 20,
|
||||
limit: 20
|
||||
}
|
||||
|
||||
if (cursor.value) {
|
||||
@@ -32,7 +33,7 @@ export function useFollowingNoteList(
|
||||
const response = await fetch("https://api.remanso.space/notes/feed", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
|
||||
const data: { notes: PublicNoteListItem[]; cursor?: string } =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Ref, ref, watch } from 'vue'
|
||||
import { Ref, ref, watch } from "vue"
|
||||
|
||||
import { getFollows } from '@/modules/atproto/service/getFollows'
|
||||
import { getFollows } from "@/modules/atproto/service/getFollows"
|
||||
|
||||
export const useFollows = (did: Ref<string | null>) => {
|
||||
const follows = ref<Set<string>>(new Set())
|
||||
@@ -14,7 +14,7 @@ export const useFollows = (did: Ref<string | null>) => {
|
||||
follows.value = new Set()
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
return { follows }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ref } from "vue"
|
||||
import { useRouter } from "vue-router"
|
||||
|
||||
export const useForm = () => {
|
||||
const userInput = ref('')
|
||||
const repoInput = ref('')
|
||||
const userInput = ref("")
|
||||
const repoInput = ref("")
|
||||
const { push } = useRouter()
|
||||
|
||||
const submit = () => {
|
||||
@@ -12,7 +12,7 @@ export const useForm = () => {
|
||||
}
|
||||
|
||||
push({
|
||||
name: 'FluxNoteView',
|
||||
name: "FluxNoteView",
|
||||
params: {
|
||||
user: userInput.value,
|
||||
repo: repoInput.value
|
||||
|
||||
@@ -4,7 +4,7 @@ import { confirmMessage, errorMessage } from "@/utils/notif"
|
||||
|
||||
export const useGitHubContent = ({
|
||||
user,
|
||||
repo,
|
||||
repo
|
||||
}: {
|
||||
user: string
|
||||
repo: string
|
||||
@@ -12,7 +12,7 @@ export const useGitHubContent = ({
|
||||
const putFile = async ({
|
||||
content,
|
||||
path,
|
||||
sha,
|
||||
sha
|
||||
}: {
|
||||
content: string
|
||||
path: string
|
||||
@@ -29,8 +29,8 @@ export const useGitHubContent = ({
|
||||
path,
|
||||
message: `Updating ${path} from Remanso`,
|
||||
content: encodeUTF8ToBase64(content),
|
||||
sha,
|
||||
},
|
||||
sha
|
||||
}
|
||||
)
|
||||
|
||||
confirmMessage("✅ Note saved")
|
||||
@@ -48,6 +48,6 @@ export const useGitHubContent = ({
|
||||
updateFile: async (props: { content: string; path: string; sha: string }) =>
|
||||
putFile(props),
|
||||
createFile: async (props: { content: string; path: string }) =>
|
||||
putFile(props),
|
||||
putFile(props)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, ref } from "vue"
|
||||
|
||||
import { GithubToken } from '@/modules/user/interfaces/GithubToken'
|
||||
import { getAccessToken, saveAccessToken } from '@/modules/user/service/signIn'
|
||||
import { confirmMessage } from '@/utils/notif'
|
||||
import { GithubToken } from "@/modules/user/interfaces/GithubToken"
|
||||
import { getAccessToken, saveAccessToken } from "@/modules/user/service/signIn"
|
||||
import { confirmMessage } from "@/utils/notif"
|
||||
|
||||
const username = ref<string | null>(null)
|
||||
const accessToken = ref<string | null>(null)
|
||||
@@ -11,8 +11,8 @@ let init = true
|
||||
|
||||
const saveAccessTokenToLocal = async () => {
|
||||
const response = await getAccessToken()
|
||||
username.value = response?.username || ''
|
||||
accessToken.value = response?.token || ''
|
||||
username.value = response?.username || ""
|
||||
accessToken.value = response?.token || ""
|
||||
}
|
||||
|
||||
const saveCredentials = async (token: GithubToken): Promise<void> => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { computed, watch } from 'vue'
|
||||
import { computed, watch } from "vue"
|
||||
|
||||
import { useFile } from '@/hooks/useFile.hook'
|
||||
import { resolvePath } from '@/modules/repo/services/resolvePath'
|
||||
import { useUserRepoStore } from '@/modules/repo/store/userRepo.store'
|
||||
import { useFile } from "@/hooks/useFile.hook"
|
||||
import { resolvePath } from "@/modules/repo/services/resolvePath"
|
||||
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
|
||||
|
||||
const SRC_PREFIX = 'data:image/jpeg;charset=utf-8;base64,'
|
||||
const SRC_PREFIX = "data:image/jpeg;charset=utf-8;base64,"
|
||||
|
||||
export const useImages = (sha: string) => {
|
||||
const store = useUserRepoStore()
|
||||
@@ -23,14 +23,14 @@ export const useImages = (sha: string) => {
|
||||
const images = document.querySelectorAll(`.note-${sha} img`)
|
||||
|
||||
images.forEach(async (image) => {
|
||||
const src = image.getAttribute('src')
|
||||
const src = image.getAttribute("src")
|
||||
if (!src || src.startsWith(SRC_PREFIX)) {
|
||||
return
|
||||
}
|
||||
|
||||
const imageFilePath = resolvePath(
|
||||
filePath,
|
||||
image.getAttribute('src') ?? ''
|
||||
image.getAttribute("src") ?? ""
|
||||
)
|
||||
|
||||
const imageFile = store.files.find(
|
||||
@@ -43,7 +43,7 @@ export const useImages = (sha: string) => {
|
||||
const { getCachedFileContent } = useFile(imageFile.sha, false)
|
||||
|
||||
const fileContent = await getCachedFileContent()
|
||||
image.setAttribute('src', `${SRC_PREFIX} ${fileContent}`)
|
||||
image.setAttribute("src", `${SRC_PREFIX} ${fileContent}`)
|
||||
})
|
||||
},
|
||||
{ immediate: true }
|
||||
|
||||
@@ -6,7 +6,7 @@ import { isExternalLink } from "@/utils/link"
|
||||
|
||||
export const useLinks = (
|
||||
className: ComputedRef<string> | string,
|
||||
sha?: Ref<string> | string,
|
||||
sha?: Ref<string> | string
|
||||
) => {
|
||||
const store = useUserRepoStore()
|
||||
|
||||
@@ -34,7 +34,7 @@ export const useLinks = (
|
||||
path: href,
|
||||
currentNoteSHA: toValue(sha),
|
||||
user: store.user,
|
||||
repo: store.repo,
|
||||
repo: store.repo
|
||||
})
|
||||
}
|
||||
|
||||
@@ -74,6 +74,6 @@ export const useLinks = (
|
||||
})
|
||||
|
||||
return {
|
||||
listenToClick,
|
||||
listenToClick
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import markdownItKatex from "@vscode/markdown-it-katex"
|
||||
import MarkdownIt, { Options } from "markdown-it"
|
||||
import Renderer, { type RenderRuleRecord } from "markdown-it/lib/renderer.mjs"
|
||||
import type Token from "markdown-it/lib/token.mjs"
|
||||
import blockEmbedPlugin from "markdown-it-block-embed"
|
||||
import markdownItCheckbox from "markdown-it-checkbox"
|
||||
import MarkdownItGitHubAlerts from "markdown-it-github-alerts"
|
||||
import markdownItIframe from "markdown-it-iframe"
|
||||
import Shikiji from "markdown-it-shikiji"
|
||||
import mermaid from "mermaid"
|
||||
import { Ref, toValue } from "vue"
|
||||
|
||||
import { decodeBase64ToUTF8 } from "@/utils/decodeBase64ToUTF8"
|
||||
import { html5Media } from "@/utils/markdown/markdown-html5-media"
|
||||
import { markdownItTablerIcons } from "@/utils/markdown/markdown-it-tabler-icons"
|
||||
import mermaid from "mermaid"
|
||||
import type Token from "markdown-it/lib/token.mjs"
|
||||
import Renderer, { type RenderRuleRecord } from "markdown-it/lib/renderer.mjs"
|
||||
|
||||
const markdownItMermaidExtractor = (md: MarkdownIt) => {
|
||||
const defaultFence =
|
||||
@@ -22,7 +22,7 @@ const markdownItMermaidExtractor = (md: MarkdownIt) => {
|
||||
index: number,
|
||||
options: Options,
|
||||
_: unknown,
|
||||
self: Renderer,
|
||||
self: Renderer
|
||||
) {
|
||||
return self.renderToken(tokens, index, options)
|
||||
}
|
||||
@@ -32,7 +32,7 @@ const markdownItMermaidExtractor = (md: MarkdownIt) => {
|
||||
index: number,
|
||||
options: Options,
|
||||
env: unknown,
|
||||
self: Renderer,
|
||||
self: Renderer
|
||||
) {
|
||||
const token = tokens[index]
|
||||
|
||||
@@ -47,20 +47,20 @@ const markdownItMermaidExtractor = (md: MarkdownIt) => {
|
||||
|
||||
const md = new MarkdownIt({
|
||||
typographer: true,
|
||||
quotes: ["«\xA0", "\xA0»", "‹\xA0", "\xA0›"],
|
||||
quotes: ["«\xA0", "\xA0»", "‹\xA0", "\xA0›"]
|
||||
})
|
||||
.use(markdownItMermaidExtractor)
|
||||
.use(html5Media)
|
||||
.use(blockEmbedPlugin, {
|
||||
youtube: {
|
||||
width: "100%",
|
||||
height: 300,
|
||||
},
|
||||
height: 300
|
||||
}
|
||||
})
|
||||
.use(markdownItCheckbox)
|
||||
.use(markdownItKatex)
|
||||
.use(markdownItIframe, {
|
||||
width: "100%",
|
||||
width: "100%"
|
||||
})
|
||||
.use(MarkdownItGitHubAlerts)
|
||||
.use(markdownItTablerIcons)
|
||||
@@ -77,7 +77,7 @@ export const useShikiji = async () => {
|
||||
await Shikiji({
|
||||
themes: {
|
||||
light: "vitesse-light",
|
||||
dark: "vitesse-black",
|
||||
dark: "vitesse-black"
|
||||
},
|
||||
langs: [
|
||||
"bash",
|
||||
@@ -87,9 +87,9 @@ export const useShikiji = async () => {
|
||||
"mermaid",
|
||||
"html",
|
||||
"css",
|
||||
"json",
|
||||
],
|
||||
}),
|
||||
"json"
|
||||
]
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -101,19 +101,19 @@ export const runMermaid = (querySelector: string) => {
|
||||
mermaid.initialize({
|
||||
theme: "dark",
|
||||
startOnLoad: false,
|
||||
flowchart: { curve: "natural" },
|
||||
flowchart: { curve: "natural" }
|
||||
})
|
||||
}
|
||||
|
||||
mermaid.run({
|
||||
querySelector,
|
||||
querySelector
|
||||
})
|
||||
}
|
||||
|
||||
const rules: RenderRuleRecord = {
|
||||
table_open: () =>
|
||||
'<div class="overflow-x-auto"><table class="table table-zebra">',
|
||||
table_close: () => "</table></div>",
|
||||
table_close: () => "</table></div>"
|
||||
}
|
||||
|
||||
md.renderer.rules = { ...md.renderer.rules, ...rules }
|
||||
@@ -128,7 +128,7 @@ export const markdownBuilder = (defaultPrefix?: Ref<string> | string) => {
|
||||
const renderFromUTF8 = (content: string, prefix?: string) => {
|
||||
return content
|
||||
? md.render(stripFrontmatter(content), {
|
||||
docId: defaultPrefix ? toValue(defaultPrefix) : (prefix ?? ""),
|
||||
docId: defaultPrefix ? toValue(defaultPrefix) : (prefix ?? "")
|
||||
})
|
||||
: ""
|
||||
}
|
||||
@@ -139,6 +139,6 @@ export const markdownBuilder = (defaultPrefix?: Ref<string> | string) => {
|
||||
render: (content: string, prefix?: string) =>
|
||||
renderFromUTF8(decodeBase64ToUTF8(content), prefix),
|
||||
renderFromUTF8,
|
||||
getRawContent,
|
||||
getRawContent
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { computed, onMounted, Ref, ref, toValue } from "vue"
|
||||
|
||||
import { BOOKMARK_WIDTH_REM, getBookmarkWidthPx } from "@/constants/bookmark-width"
|
||||
import {
|
||||
BOOKMARK_WIDTH_REM,
|
||||
getBookmarkWidthPx
|
||||
} from "@/constants/bookmark-width"
|
||||
import { getNoteWidth } from "@/constants/note-width"
|
||||
import { useOverlay } from "@/hooks/useOverlay.hook"
|
||||
import { useRouteQueryStackedNotes } from "@/hooks/useRouteQueryStackedNotes.hook"
|
||||
|
||||
export const useNoteOverlay = (
|
||||
className: string,
|
||||
index: Ref<number> | number,
|
||||
index: Ref<number> | number
|
||||
) => {
|
||||
const { x, y, isMobile } = useOverlay()
|
||||
const noteHeight = ref(0)
|
||||
@@ -18,14 +21,17 @@ export const useNoteOverlay = (
|
||||
if (isMobile.value) {
|
||||
return y.value > valueIndex * noteHeight.value
|
||||
} else {
|
||||
return x.value > valueIndex * getNoteWidth() - valueIndex * getBookmarkWidthPx()
|
||||
return (
|
||||
x.value >
|
||||
valueIndex * getNoteWidth() - valueIndex * getBookmarkWidthPx()
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
const { stackedNotes } = useRouteQueryStackedNotes()
|
||||
const noteElement = document.querySelector(
|
||||
`.${className}`,
|
||||
`.${className}`
|
||||
) satisfies HTMLElement | null
|
||||
|
||||
if (!noteElement) {
|
||||
@@ -40,7 +46,7 @@ export const useNoteOverlay = (
|
||||
noteElement.style.left = `${(toValue(index) + 1) * BOOKMARK_WIDTH_REM}rem`
|
||||
|
||||
const stackedNoteContainers = document.querySelectorAll(
|
||||
".stacked-note",
|
||||
".stacked-note"
|
||||
) satisfies NodeListOf<HTMLElement>
|
||||
|
||||
stackedNoteContainers.forEach((stackedNote, ind) => {
|
||||
@@ -52,6 +58,6 @@ export const useNoteOverlay = (
|
||||
})
|
||||
|
||||
return {
|
||||
displayNoteOverlay,
|
||||
displayNoteOverlay
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ export const useNoteView = () => {
|
||||
obj[note] = pathToNotePathTitle(filePath)
|
||||
|
||||
return obj
|
||||
}, {}),
|
||||
}, {})
|
||||
)
|
||||
|
||||
const unsubscribeLink = noteEventBus.addEventBusListener(
|
||||
({ path, currentNoteSHA }) => {
|
||||
const currentFile = store.files.find(
|
||||
(file) => file.sha === currentNoteSHA,
|
||||
(file) => file.sha === currentNoteSHA
|
||||
)
|
||||
|
||||
const absolutePath = resolvePath(currentFile?.path ?? "", path)
|
||||
@@ -39,7 +39,7 @@ export const useNoteView = () => {
|
||||
}
|
||||
|
||||
addStackedNote(currentNoteSHA ?? "", file.sha)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -47,6 +47,6 @@ export const useNoteView = () => {
|
||||
})
|
||||
|
||||
return {
|
||||
titles,
|
||||
titles
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useAsyncState } from '@vueuse/core'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useAsyncState } from "@vueuse/core"
|
||||
import { computed, ref } from "vue"
|
||||
|
||||
import { data } from '@/data/data'
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { prepareNoteCache } from '@/modules/note/cache/prepareNoteCache'
|
||||
import { Note } from '@/modules/note/models/Note'
|
||||
import { queryFileContent } from '@/modules/repo/services/repo'
|
||||
import { useUserRepoStore } from '@/modules/repo/store/userRepo.store'
|
||||
import { data } from "@/data/data"
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { prepareNoteCache } from "@/modules/note/cache/prepareNoteCache"
|
||||
import { Note } from "@/modules/note/models/Note"
|
||||
import { queryFileContent } from "@/modules/repo/services/repo"
|
||||
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
|
||||
|
||||
export const useOfflineNotes = () => {
|
||||
const store = useUserRepoStore()
|
||||
|
||||
@@ -19,11 +19,11 @@ export const useOverlay = (listen = true) => {
|
||||
}
|
||||
useEventListener(window, "scroll", updateScroll, {
|
||||
passive: true,
|
||||
capture: false,
|
||||
capture: false
|
||||
})
|
||||
useEventListener(document.body, "scroll", updateScroll, {
|
||||
passive: true,
|
||||
capture: false,
|
||||
capture: false
|
||||
})
|
||||
}
|
||||
|
||||
@@ -47,6 +47,6 @@ export const useOverlay = (listen = true) => {
|
||||
x,
|
||||
y,
|
||||
isMobile,
|
||||
scrollToNote,
|
||||
scrollToNote
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { computedAsync } from "@vueuse/core"
|
||||
import { computed, Ref, ref } from "vue"
|
||||
|
||||
import { Author, getAuthors } from "@/modules/atproto/getAuthor"
|
||||
import { PublicNoteListItem } from "@/modules/note/models/Note"
|
||||
import { computedAsync } from "@vueuse/core"
|
||||
import { computed, ref, Ref } from "vue"
|
||||
|
||||
interface UsePublicNoteListOptions {
|
||||
did?: Ref<string | undefined>
|
||||
@@ -50,6 +51,6 @@ export function usePublicNoteList(options?: UsePublicNoteListOptions) {
|
||||
canLoadMore,
|
||||
onLoadMore,
|
||||
authors,
|
||||
getAuthor,
|
||||
getAuthor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useAsyncState } from '@vueuse/core'
|
||||
import { useAsyncState } from "@vueuse/core"
|
||||
|
||||
import { useGitHubLogin } from '@/hooks/useGitHubLogin.hook'
|
||||
import { RepoBase } from '@/modules/repo/interfaces/RepoBase'
|
||||
import { getOctokit } from '@/modules/repo/services/octo'
|
||||
import { useGitHubLogin } from "@/hooks/useGitHubLogin.hook"
|
||||
import { RepoBase } from "@/modules/repo/interfaces/RepoBase"
|
||||
import { getOctokit } from "@/modules/repo/services/octo"
|
||||
|
||||
export const useRepos = () => {
|
||||
const { username, accessToken } = useGitHubLogin()
|
||||
@@ -13,7 +13,7 @@ export const useRepos = () => {
|
||||
|
||||
const octokit = await getOctokit()
|
||||
|
||||
const repoList = await octokit.request('GET /search/repositories', {
|
||||
const repoList = await octokit.request("GET /search/repositories", {
|
||||
q: `user:${username.value}`,
|
||||
per_page: 100
|
||||
})
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { onMounted, watch, type Ref } from "vue"
|
||||
import { onMounted, type Ref, watch } from "vue"
|
||||
|
||||
import { getNoteWidth } from "@/constants/note-width"
|
||||
import { useOverlay } from "@/hooks/useOverlay.hook"
|
||||
|
||||
export const useResizeContainer = (
|
||||
containerClass: string,
|
||||
stackedNotes: Readonly<Ref<readonly string[]>>,
|
||||
stackedNotes: Readonly<Ref<readonly string[]>>
|
||||
) => {
|
||||
const { isMobile } = useOverlay(false)
|
||||
|
||||
const resizeContainer = () => {
|
||||
const container = document.querySelector(
|
||||
`.${containerClass}`,
|
||||
`.${containerClass}`
|
||||
) as HTMLElement | null
|
||||
|
||||
if (!container) {
|
||||
@@ -32,6 +32,6 @@ export const useResizeContainer = (
|
||||
})
|
||||
|
||||
watch(stackedNotes, resizeContainer, {
|
||||
immediate: true,
|
||||
immediate: true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export const useRouteQueryStackedNotes = () => {
|
||||
}
|
||||
|
||||
return Array.isArray(value) ? value : [value]
|
||||
},
|
||||
}
|
||||
})
|
||||
const { height } = useWindowSize()
|
||||
|
||||
@@ -22,7 +22,7 @@ export const useRouteQueryStackedNotes = () => {
|
||||
|
||||
const scrollToFocusedNote = (
|
||||
noteId: string | null = null,
|
||||
notes: string[] = stackedNotes.value,
|
||||
notes: string[] = stackedNotes.value
|
||||
) => {
|
||||
nextTick(() => {
|
||||
const index = noteId ? notes.findIndex((nid) => nid === noteId) : 0
|
||||
@@ -31,7 +31,7 @@ export const useRouteQueryStackedNotes = () => {
|
||||
if (noteId) {
|
||||
const cleanNoteId = noteId.replaceAll(":", "-")
|
||||
const element = document.querySelector(
|
||||
`.note-${cleanNoteId}`,
|
||||
`.note-${cleanNoteId}`
|
||||
) as HTMLElement
|
||||
|
||||
const top = (index + 1) * (element?.clientHeight ?? height.value)
|
||||
@@ -53,7 +53,7 @@ export const useRouteQueryStackedNotes = () => {
|
||||
const addStackedNote = (
|
||||
currentSha: string,
|
||||
sha: string,
|
||||
selector?: string,
|
||||
selector?: string
|
||||
) => {
|
||||
if (stackedNotes.value.includes(sha)) {
|
||||
scrollToFocusedNote(selector ?? sha)
|
||||
@@ -70,7 +70,7 @@ export const useRouteQueryStackedNotes = () => {
|
||||
const newStackedNotes = [
|
||||
...splittedStackedNotes.replaceAll(";;", ";").split(";"),
|
||||
currentSha,
|
||||
sha,
|
||||
sha
|
||||
].filter((sha) => !!sha)
|
||||
|
||||
stackedNotes.value = newStackedNotes
|
||||
@@ -82,6 +82,6 @@ export const useRouteQueryStackedNotes = () => {
|
||||
return {
|
||||
stackedNotes: readonly(stackedNotes),
|
||||
addStackedNote,
|
||||
scrollToFocusedNote,
|
||||
scrollToFocusedNote
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { useTitle } from '@vueuse/core'
|
||||
import { computed, Ref, toValue, watch } from 'vue'
|
||||
import { useTitle } from "@vueuse/core"
|
||||
import { computed, Ref, toValue, watch } from "vue"
|
||||
|
||||
import { useRouteQueryStackedNotes } from '@/hooks/useRouteQueryStackedNotes.hook'
|
||||
import { useNotes } from '@/modules/note/hooks/useNotes'
|
||||
import { pathToNoteTitle } from '@/utils/noteTitle'
|
||||
import { useRouteQueryStackedNotes } from "@/hooks/useRouteQueryStackedNotes.hook"
|
||||
import { useNotes } from "@/modules/note/hooks/useNotes"
|
||||
import { pathToNoteTitle } from "@/utils/noteTitle"
|
||||
|
||||
export const generateTitle = (titles: string[]) => titles.join(' | ')
|
||||
export const generateTitle = (titles: string[]) => titles.join(" | ")
|
||||
|
||||
export const useTitleNotes = (prefix: Ref<string> | string) => {
|
||||
const { stackedNotes } = useRouteQueryStackedNotes()
|
||||
const { notes } = useNotes()
|
||||
const titleNotes = computed(() =>
|
||||
notes.value
|
||||
.filter((note) => stackedNotes.value.includes(note.sha ?? ''))
|
||||
.map((note) => pathToNoteTitle(note.path ?? ''))
|
||||
.filter((note) => stackedNotes.value.includes(note.sha ?? ""))
|
||||
.map((note) => pathToNoteTitle(note.path ?? ""))
|
||||
)
|
||||
|
||||
const title = useTitle(generateTitle([toValue(prefix), ...titleNotes.value]))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import en from './en.json'
|
||||
import fr from './fr.json'
|
||||
import en from "./en.json"
|
||||
import fr from "./fr.json"
|
||||
|
||||
export const messages = {
|
||||
en,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import "notyf/notyf.min.css"
|
||||
import "./styles/app.css"
|
||||
import "@/analytics/openpanel"
|
||||
|
||||
import { VueQueryPlugin } from "@tanstack/vue-query"
|
||||
import { createPinia } from "pinia"
|
||||
@@ -10,11 +11,10 @@ import { messages } from "@/locales/message"
|
||||
import { router } from "@/router/router"
|
||||
|
||||
import App from "./App.vue"
|
||||
import "@/analytics/openpanel"
|
||||
|
||||
const i18n = createI18n({
|
||||
locale: "en",
|
||||
messages,
|
||||
messages
|
||||
})
|
||||
|
||||
createApp(App)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createSchema, createFetch } from "@better-fetch/fetch"
|
||||
import { createFetch, createSchema } from "@better-fetch/fetch"
|
||||
import { type } from "arktype"
|
||||
|
||||
export type Author = { handle: string; pds: string }
|
||||
@@ -12,20 +12,20 @@ const schema = createSchema(
|
||||
did: "string",
|
||||
handle: "string",
|
||||
pds: "string",
|
||||
signing_key: "string",
|
||||
signing_key: "string"
|
||||
}),
|
||||
query: type({
|
||||
identifier: "string",
|
||||
}),
|
||||
},
|
||||
identifier: "string"
|
||||
})
|
||||
}
|
||||
},
|
||||
{ strict: true },
|
||||
{ strict: true }
|
||||
)
|
||||
|
||||
const microcosmSlingshot = createFetch({
|
||||
baseURL: "https://slingshot.microcosm.blue",
|
||||
// plugins: [logger()],
|
||||
schema,
|
||||
schema
|
||||
})
|
||||
|
||||
export const getAuthor = async (did: string): Promise<Author | null> => {
|
||||
@@ -36,7 +36,7 @@ export const getAuthor = async (did: string): Promise<Author | null> => {
|
||||
try {
|
||||
const { data: author } = await microcosmSlingshot(
|
||||
"/xrpc/blue.microcosm.identity.resolveMiniDoc",
|
||||
{ query: { identifier: did } },
|
||||
{ query: { identifier: did } }
|
||||
)
|
||||
|
||||
if (!author) {
|
||||
@@ -62,7 +62,7 @@ export const getAuthors = async (dids: Set<string>) => {
|
||||
|
||||
const { data: author } = await microcosmSlingshot(
|
||||
"/xrpc/blue.microcosm.identity.resolveMiniDoc",
|
||||
{ query: { identifier: did } },
|
||||
{ query: { identifier: did } }
|
||||
)
|
||||
|
||||
if (!author) {
|
||||
@@ -72,7 +72,7 @@ export const getAuthors = async (dids: Set<string>) => {
|
||||
correspondanceCache.set(did, author)
|
||||
|
||||
return [did, author] as [string, Author | null]
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
return new Map(correspondance)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
BrowserOAuthClient,
|
||||
buildLoopbackClientId,
|
||||
buildLoopbackClientId
|
||||
} from "@atproto/oauth-client-browser"
|
||||
|
||||
const getClientId = () =>
|
||||
@@ -14,7 +14,7 @@ export const getOAuthClient = (): Promise<BrowserOAuthClient> => {
|
||||
if (!clientPromise) {
|
||||
clientPromise = BrowserOAuthClient.load({
|
||||
clientId: getClientId(),
|
||||
handleResolver: "https://bsky.social",
|
||||
handleResolver: "https://bsky.social"
|
||||
})
|
||||
}
|
||||
return clientPromise
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { data } from '@/data/data'
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { AtprotoSession } from '@/data/models/AtprotoSession'
|
||||
import { data } from "@/data/data"
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { AtprotoSession } from "@/data/models/AtprotoSession"
|
||||
|
||||
const SESSION_ID = `${DataType.AtprotoSession}-current`
|
||||
|
||||
@@ -8,12 +8,15 @@ export const loadSession = (): Promise<AtprotoSession | null> => {
|
||||
return data.get<DataType.AtprotoSession, AtprotoSession>(SESSION_ID)
|
||||
}
|
||||
|
||||
export const saveSession = async (did: string, handle: string): Promise<void> => {
|
||||
export const saveSession = async (
|
||||
did: string,
|
||||
handle: string
|
||||
): Promise<void> => {
|
||||
const session: AtprotoSession = {
|
||||
_id: SESSION_ID,
|
||||
$type: DataType.AtprotoSession,
|
||||
did,
|
||||
handle,
|
||||
handle
|
||||
}
|
||||
await data.update<DataType.AtprotoSession, AtprotoSession>(session)
|
||||
}
|
||||
|
||||
@@ -3,15 +3,18 @@ export const getFollows = async (did: string): Promise<Set<string>> => {
|
||||
let cursor: string | undefined
|
||||
|
||||
do {
|
||||
const url = new URL('https://public.api.bsky.app/xrpc/app.bsky.graph.getFollows')
|
||||
url.searchParams.set('actor', did)
|
||||
url.searchParams.set('limit', '100')
|
||||
const url = new URL(
|
||||
"https://public.api.bsky.app/xrpc/app.bsky.graph.getFollows"
|
||||
)
|
||||
url.searchParams.set("actor", did)
|
||||
url.searchParams.set("limit", "100")
|
||||
if (cursor) {
|
||||
url.searchParams.set('cursor', cursor)
|
||||
url.searchParams.set("cursor", cursor)
|
||||
}
|
||||
|
||||
const response = await fetch(url)
|
||||
const result: { follows: { did: string }[]; cursor?: string } = await response.json()
|
||||
const result: { follows: { did: string }[]; cursor?: string } =
|
||||
await response.json()
|
||||
|
||||
for (const follow of result.follows) {
|
||||
follows.add(follow.did)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const withATProtoImages = (
|
||||
markdown: string,
|
||||
{ pds, did }: { pds: string; did: string },
|
||||
{ pds, did }: { pds: string; did: string }
|
||||
): string => {
|
||||
const imageLinkPattern = /!\[([^\]]*)\]\((bafkrei[a-z0-9]+)\)/g
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, ref } from "vue"
|
||||
|
||||
import FlipCard from '@/modules/card/components/FlipCard.vue'
|
||||
import { Repetition } from '@/modules/card/hooks/useSpacedRepetitionCards'
|
||||
import FlipCard from "@/modules/card/components/FlipCard.vue"
|
||||
import { Repetition } from "@/modules/card/hooks/useSpacedRepetitionCards"
|
||||
|
||||
const props = defineProps<{ cards: Repetition[] }>()
|
||||
const emits = defineEmits<{
|
||||
@@ -22,24 +22,24 @@ const sortedCards = ref(
|
||||
const currentIndex = ref(0)
|
||||
|
||||
const goToNextCard = (success: boolean) => {
|
||||
const id = sortedCards.value[currentIndex.value].repetition._id ?? ''
|
||||
const id = sortedCards.value[currentIndex.value].repetition._id ?? ""
|
||||
|
||||
if (success) {
|
||||
emits('success', id)
|
||||
emits("success", id)
|
||||
} else {
|
||||
const failedCard = sortedCards.value.at(currentIndex.value)
|
||||
if (failedCard) {
|
||||
sortedCards.value.push(failedCard)
|
||||
}
|
||||
emits('fail', id)
|
||||
emits("fail", id)
|
||||
}
|
||||
|
||||
currentIndex.value++
|
||||
}
|
||||
|
||||
const needsReview = () => {
|
||||
const id = sortedCards.value[currentIndex.value].repetition._id ?? ''
|
||||
emits('needsReview', id)
|
||||
const id = sortedCards.value[currentIndex.value].repetition._id ?? ""
|
||||
emits("needsReview", id)
|
||||
currentIndex.value++
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useAsyncState } from '@vueuse/core'
|
||||
import { useAsyncState } from "@vueuse/core"
|
||||
|
||||
import { data } from '@/data/data'
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { RepetitionCard } from '@/modules/card/models/RepetitionCard'
|
||||
import { data } from "@/data/data"
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { RepetitionCard } from "@/modules/card/models/RepetitionCard"
|
||||
|
||||
export const useNeedReviewCards = () => {
|
||||
const { state: cardsToReview, isReady } = useAsyncState(async () => {
|
||||
|
||||
@@ -31,14 +31,14 @@ export const useSpacedRepetitionCards = () => {
|
||||
(file) =>
|
||||
file.path !== undefined &&
|
||||
file.path.startsWith("_cards") &&
|
||||
file.path.endsWith(".md"),
|
||||
),
|
||||
file.path.endsWith(".md")
|
||||
)
|
||||
)
|
||||
|
||||
const {
|
||||
state: cards,
|
||||
isReady,
|
||||
execute,
|
||||
execute
|
||||
} = useAsyncState(
|
||||
async () => {
|
||||
const cards: Repetition[] = []
|
||||
@@ -55,7 +55,7 @@ export const useSpacedRepetitionCards = () => {
|
||||
$type: DataType.RepetitionCard,
|
||||
level: 1,
|
||||
repeatDate: new Date(),
|
||||
needsReview: false,
|
||||
needsReview: false
|
||||
})
|
||||
|
||||
if (
|
||||
@@ -77,20 +77,20 @@ export const useSpacedRepetitionCards = () => {
|
||||
card: {
|
||||
front: toHTML(front),
|
||||
back: toHTML(back),
|
||||
references: toHTML(references),
|
||||
},
|
||||
references: toHTML(references)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return cards
|
||||
},
|
||||
[],
|
||||
{ immediate: false },
|
||||
{ immediate: false }
|
||||
)
|
||||
|
||||
const successRepetition = async (cardId: string) => {
|
||||
const repetition = await data.get<DataType.RepetitionCard, RepetitionCard>(
|
||||
cardId,
|
||||
cardId
|
||||
)
|
||||
if (!repetition) {
|
||||
return
|
||||
@@ -100,13 +100,13 @@ export const useSpacedRepetitionCards = () => {
|
||||
...repetition,
|
||||
needsReview: false,
|
||||
level: Math.min(repetition.level + 1, MAX_LEVEL),
|
||||
repeatDate: addDays(new Date(), 2 ** repetition.level),
|
||||
repeatDate: addDays(new Date(), 2 ** repetition.level)
|
||||
})
|
||||
}
|
||||
|
||||
const failRepetition = async (cardId: string) => {
|
||||
const repetition = await data.get<DataType.RepetitionCard, RepetitionCard>(
|
||||
cardId,
|
||||
cardId
|
||||
)
|
||||
if (!repetition) {
|
||||
return
|
||||
@@ -118,13 +118,13 @@ export const useSpacedRepetitionCards = () => {
|
||||
...repetition,
|
||||
level,
|
||||
needsReview: false,
|
||||
repeatDate: addDays(new Date(), level),
|
||||
repeatDate: addDays(new Date(), level)
|
||||
})
|
||||
}
|
||||
|
||||
const needsReview = async (cardId: string) => {
|
||||
const repetition = await data.get<DataType.RepetitionCard, RepetitionCard>(
|
||||
cardId,
|
||||
cardId
|
||||
)
|
||||
if (!repetition) {
|
||||
return
|
||||
@@ -132,7 +132,7 @@ export const useSpacedRepetitionCards = () => {
|
||||
|
||||
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
||||
...repetition,
|
||||
needsReview: true,
|
||||
needsReview: true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ export const useSpacedRepetitionCards = () => {
|
||||
nextTick(() => {
|
||||
listenToClick()
|
||||
}),
|
||||
{ immediate: true },
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(cardFiles, () => execute())
|
||||
@@ -152,6 +152,6 @@ export const useSpacedRepetitionCards = () => {
|
||||
successRepetition,
|
||||
failRepetition,
|
||||
needsReview,
|
||||
isLoading: !isReady,
|
||||
isLoading: !isReady
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { Model } from '@/data/models/Model'
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { Model } from "@/data/models/Model"
|
||||
|
||||
export interface RepetitionCard extends Model<DataType.RepetitionCard> {
|
||||
level: number
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { useLastVisitedRepos } from '@/modules/history/hooks/useLastVisitedRepos.hook'
|
||||
import { useLastVisitedRepos } from "@/modules/history/hooks/useLastVisitedRepos.hook"
|
||||
|
||||
const { lastVisitedRepos } = useLastVisitedRepos()
|
||||
</script>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { useAsyncState } from '@vueuse/core'
|
||||
import { computed } from 'vue'
|
||||
import { useAsyncState } from "@vueuse/core"
|
||||
import { computed } from "vue"
|
||||
|
||||
import { data } from '@/data/data'
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { History } from '@/data/models/History'
|
||||
import { data } from "@/data/data"
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { History } from "@/data/models/History"
|
||||
|
||||
const HISTORY_ID = data.generateId(DataType.History, 'history')
|
||||
const HISTORY_ID = data.generateId(DataType.History, "history")
|
||||
|
||||
export const useLastVisitedRepos = () => {
|
||||
const history = useAsyncState(
|
||||
() =>
|
||||
data.get<DataType.History, History>(
|
||||
data.generateId(DataType.History, 'history')
|
||||
data.generateId(DataType.History, "history")
|
||||
),
|
||||
null
|
||||
)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Ref, toValue } from 'vue'
|
||||
import { Ref, toValue } from "vue"
|
||||
|
||||
import { data } from '@/data/data'
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { History } from '@/data/models/History'
|
||||
import { data } from "@/data/data"
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { History } from "@/data/models/History"
|
||||
|
||||
const HISTORY_ID = data.generateId(DataType.History, 'history')
|
||||
const HISTORY_ID = data.generateId(DataType.History, "history")
|
||||
const MAX_REPO_HISTORY = 10
|
||||
|
||||
export const useVisitRepo = (newRepo: {
|
||||
|
||||
16
src/modules/note/cache/prepareNoteCache.ts
vendored
16
src/modules/note/cache/prepareNoteCache.ts
vendored
@@ -1,14 +1,14 @@
|
||||
import { data } from '@/data/data'
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { Note } from '@/modules/note/models/Note'
|
||||
import { useUserRepoStore } from '@/modules/repo/store/userRepo.store'
|
||||
import { data } from "@/data/data"
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { Note } from "@/modules/note/models/Note"
|
||||
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
|
||||
|
||||
type NoteCacheResult =
|
||||
| {
|
||||
note: Note
|
||||
from: 'sha'
|
||||
from: "sha"
|
||||
}
|
||||
| { note: Note; from: 'path' }
|
||||
| { note: Note; from: "path" }
|
||||
| { note: null; from: null }
|
||||
|
||||
export const prepareNoteCache = (sha: string, path?: string) => {
|
||||
@@ -20,7 +20,7 @@ export const prepareNoteCache = (sha: string, path?: string) => {
|
||||
const note = await data.get<DataType.Note, Note>(noteId)
|
||||
|
||||
if (note) {
|
||||
return { note, from: 'sha' }
|
||||
return { note, from: "sha" }
|
||||
}
|
||||
|
||||
if (notePath) {
|
||||
@@ -33,7 +33,7 @@ export const prepareNoteCache = (sha: string, path?: string) => {
|
||||
}
|
||||
return {
|
||||
note,
|
||||
from: 'path'
|
||||
from: "path"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { computed } from "vue"
|
||||
|
||||
import { useUserRepoStore } from "@/modules/repo/store/userRepo.store"
|
||||
|
||||
export const useFolderNotes = (folders: string[]) => {
|
||||
@@ -8,8 +9,8 @@ export const useFolderNotes = (folders: string[]) => {
|
||||
store.files.filter(
|
||||
(file) =>
|
||||
folders.some((folder) => file.path?.startsWith(folder)) &&
|
||||
file.path?.endsWith(".md"),
|
||||
),
|
||||
file.path?.endsWith(".md")
|
||||
)
|
||||
)
|
||||
|
||||
const content = computed(() =>
|
||||
@@ -23,10 +24,10 @@ export const useFolderNotes = (folders: string[]) => {
|
||||
})`
|
||||
})
|
||||
.join("\n")
|
||||
: "",
|
||||
: ""
|
||||
)
|
||||
|
||||
return {
|
||||
content,
|
||||
content
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ export const useNotes = () => {
|
||||
const store = useUserRepoStore()
|
||||
|
||||
const notes = computed(() =>
|
||||
store.files.filter((file) => file.path?.endsWith(".md")),
|
||||
store.files.filter((file) => file.path?.endsWith(".md"))
|
||||
)
|
||||
|
||||
return {
|
||||
notes,
|
||||
notes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { Model } from '@/data/models/Model'
|
||||
import { Backlink } from '@/modules/note/models/Backlink'
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { Model } from "@/data/models/Model"
|
||||
import { Backlink } from "@/modules/note/models/Backlink"
|
||||
|
||||
export interface BacklinkNote extends Model<DataType.BacklinkNote> {
|
||||
sha: string
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { initContract } from "@ts-rest/core"
|
||||
import { type } from "arktype"
|
||||
import { initQueryClient } from "@ts-rest/vue-query"
|
||||
import { type } from "arktype"
|
||||
|
||||
const PublicNoteListItem = type({
|
||||
did: "string",
|
||||
rkey: "string",
|
||||
title: "string",
|
||||
publishedAt: "string",
|
||||
createdAt: "string",
|
||||
createdAt: "string"
|
||||
})
|
||||
|
||||
export type PublicNoteListItem = typeof PublicNoteListItem.infer
|
||||
@@ -18,7 +18,7 @@ const PublicNote = type({
|
||||
title: "string",
|
||||
content: "string",
|
||||
publishedAt: "string",
|
||||
createdAt: "string",
|
||||
createdAt: "string"
|
||||
})
|
||||
|
||||
export type PublicNote = typeof PublicNote.infer
|
||||
@@ -31,34 +31,34 @@ export const noteRouter = contract.router({
|
||||
path: "/notes",
|
||||
query: type({
|
||||
cursor: "string | undefined",
|
||||
limit: "number | undefined",
|
||||
limit: "number | undefined"
|
||||
}),
|
||||
responses: {
|
||||
200: type({
|
||||
notes: PublicNoteListItem.array(),
|
||||
}),
|
||||
notes: PublicNoteListItem.array()
|
||||
})
|
||||
},
|
||||
summary: "List all notes",
|
||||
summary: "List all notes"
|
||||
},
|
||||
noteListsByDid: {
|
||||
method: "GET",
|
||||
path: "/:did/notes",
|
||||
pathParams: type({
|
||||
did: "string",
|
||||
did: "string"
|
||||
}),
|
||||
query: type({
|
||||
cursor: "string | undefined",
|
||||
limit: "number | undefined",
|
||||
limit: "number | undefined"
|
||||
}),
|
||||
responses: {
|
||||
200: type({
|
||||
notes: PublicNoteListItem.array(),
|
||||
}),
|
||||
notes: PublicNoteListItem.array()
|
||||
})
|
||||
},
|
||||
summary: "List all notes",
|
||||
},
|
||||
summary: "List all notes"
|
||||
}
|
||||
})
|
||||
|
||||
export const client = initQueryClient(noteRouter, {
|
||||
baseUrl: "https://api.remanso.space",
|
||||
baseUrl: "https://api.remanso.space"
|
||||
})
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { computed, onMounted, ref } from "vue"
|
||||
|
||||
import { data } from '@/data/data'
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { useRepos } from '@/hooks/useRepos.hook'
|
||||
import { RepoBase } from '@/modules/repo/interfaces/RepoBase'
|
||||
import { FavoriteRepo } from '@/modules/repo/models/FavoriteRepo'
|
||||
import { data } from "@/data/data"
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { useRepos } from "@/hooks/useRepos.hook"
|
||||
import { RepoBase } from "@/modules/repo/interfaces/RepoBase"
|
||||
import { FavoriteRepo } from "@/modules/repo/models/FavoriteRepo"
|
||||
|
||||
export const useFavoriteRepos = () => {
|
||||
const { repos } = useRepos()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { computed } from 'vue'
|
||||
import { computed } from "vue"
|
||||
|
||||
import { useRepos } from '@/hooks/useRepos.hook'
|
||||
import { useFavoriteRepos } from '@/modules/repo/hooks/useFavoriteRepos.hook'
|
||||
import { RepoBase } from '@/modules/repo/interfaces/RepoBase'
|
||||
import { useRepos } from "@/hooks/useRepos.hook"
|
||||
import { useFavoriteRepos } from "@/modules/repo/hooks/useFavoriteRepos.hook"
|
||||
import { RepoBase } from "@/modules/repo/interfaces/RepoBase"
|
||||
|
||||
export const useRepoList = () => {
|
||||
const { savedFavoriteRepos, addFavorite, removeFavorite } = useFavoriteRepos()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { Model } from '@/data/models/Model'
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { Model } from "@/data/models/Model"
|
||||
|
||||
export interface FavoriteRepo extends Model<DataType.FavoriteRepo> {
|
||||
isFavorite: boolean
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { Model } from '@/data/models/Model'
|
||||
import { RepoFile } from '@/modules/repo/interfaces/RepoFile'
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { Model } from "@/data/models/Model"
|
||||
import { RepoFile } from "@/modules/repo/interfaces/RepoFile"
|
||||
|
||||
export interface SavedRepo extends Model<DataType.SavedRepo> {
|
||||
user: string
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Octokit } from '@octokit/rest'
|
||||
import { Octokit } from "@octokit/rest"
|
||||
|
||||
import { getAccessToken } from '@/modules/user/service/signIn'
|
||||
import { getAccessToken } from "@/modules/user/service/signIn"
|
||||
|
||||
export const getOctokit = async (): Promise<Octokit> => {
|
||||
const response = await getAccessToken()
|
||||
|
||||
return new Octokit({
|
||||
auth: response?.token ?? ''
|
||||
auth: response?.token ?? ""
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { getOctokit } from "@/modules/repo/services/octo"
|
||||
|
||||
export const getFiles = async (
|
||||
owner: string,
|
||||
repo: string,
|
||||
repo: string
|
||||
): Promise<RepoFile[]> => {
|
||||
if (!owner || !repo) {
|
||||
return []
|
||||
@@ -15,7 +15,7 @@ export const getFiles = async (
|
||||
|
||||
const commits = await octokit.request("GET /repos/{owner}/{repo}/commits", {
|
||||
owner,
|
||||
repo,
|
||||
repo
|
||||
})
|
||||
|
||||
const lastCommit = commits.data.shift()
|
||||
@@ -30,8 +30,8 @@ export const getFiles = async (
|
||||
owner,
|
||||
repo,
|
||||
tree_sha: lastCommit.commit.tree.sha,
|
||||
recursive: "true",
|
||||
},
|
||||
recursive: "true"
|
||||
}
|
||||
)
|
||||
|
||||
return treeResponse?.data.tree.filter((t) => t.type === "blob") ?? []
|
||||
@@ -60,7 +60,7 @@ export const getMainReadme = async (owner: string, repo: string) => {
|
||||
|
||||
const { render } = markdownBuilder()
|
||||
const { getCachedNote, saveCacheNote } = prepareNoteCache(
|
||||
`${owner}-${repo}-README`,
|
||||
`${owner}-${repo}-README`
|
||||
)
|
||||
|
||||
try {
|
||||
@@ -68,7 +68,7 @@ export const getMainReadme = async (owner: string, repo: string) => {
|
||||
|
||||
const README = await octokit.repos.getReadme({
|
||||
owner,
|
||||
repo,
|
||||
repo
|
||||
})
|
||||
|
||||
if (README) {
|
||||
@@ -90,7 +90,7 @@ export const getMainReadme = async (owner: string, repo: string) => {
|
||||
export const getUserSettingsContent = async (
|
||||
user: string,
|
||||
repo: string,
|
||||
files: RepoFile[],
|
||||
files: RepoFile[]
|
||||
): Promise<Omit<UserSettings, "chosenFontFamily"> | null> => {
|
||||
const configFile = files.find((file) => file.path === ".remanso.json")
|
||||
|
||||
@@ -110,7 +110,7 @@ export const getUserSettingsContent = async (
|
||||
export const queryFileContent = async (
|
||||
user: string,
|
||||
repo: string,
|
||||
sha: string,
|
||||
sha: string
|
||||
) => {
|
||||
const octokit = await getOctokit()
|
||||
|
||||
@@ -123,8 +123,8 @@ export const queryFileContent = async (
|
||||
{
|
||||
owner: user,
|
||||
repo: repo,
|
||||
file_sha: sha,
|
||||
},
|
||||
file_sha: sha
|
||||
}
|
||||
)
|
||||
|
||||
return file?.data.content ?? null
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { describe, expect, it } from "vitest"
|
||||
|
||||
import { resolvePath } from './resolvePath'
|
||||
import { resolvePath } from "./resolvePath"
|
||||
|
||||
describe('resolve path service', () => {
|
||||
it('set the absolute path if path to resolve is empty', () => {
|
||||
expect(resolvePath('standard/README.md', '')).toEqual('standard/')
|
||||
describe("resolve path service", () => {
|
||||
it("set the absolute path if path to resolve is empty", () => {
|
||||
expect(resolvePath("standard/README.md", "")).toEqual("standard/")
|
||||
})
|
||||
|
||||
it('returns the path sanitized if there is no absolute path', () => {
|
||||
expect(resolvePath('', './here/note.md')).toEqual('here/note.md')
|
||||
it("returns the path sanitized if there is no absolute path", () => {
|
||||
expect(resolvePath("", "./here/note.md")).toEqual("here/note.md")
|
||||
})
|
||||
|
||||
it('set the absolute path from the current path', () => {
|
||||
expect(resolvePath('standard/README.md', './other-note.md')).toEqual(
|
||||
'standard/other-note.md'
|
||||
it("set the absolute path from the current path", () => {
|
||||
expect(resolvePath("standard/README.md", "./other-note.md")).toEqual(
|
||||
"standard/other-note.md"
|
||||
)
|
||||
})
|
||||
|
||||
it('set the absolute path from the current path with multiple level', () => {
|
||||
it("set the absolute path from the current path with multiple level", () => {
|
||||
expect(
|
||||
resolvePath('standard/you/are/here/README.md', './other-note.md')
|
||||
).toEqual('standard/you/are/here/other-note.md')
|
||||
resolvePath("standard/you/are/here/README.md", "./other-note.md")
|
||||
).toEqual("standard/you/are/here/other-note.md")
|
||||
})
|
||||
|
||||
it('set the absolute path from the current path with a go back in the relative path', () => {
|
||||
it("set the absolute path from the current path with a go back in the relative path", () => {
|
||||
expect(
|
||||
resolvePath('standard/you/are/here/README.md', '../other-note.md')
|
||||
).toEqual('standard/you/are/other-note.md')
|
||||
resolvePath("standard/you/are/here/README.md", "../other-note.md")
|
||||
).toEqual("standard/you/are/other-note.md")
|
||||
|
||||
expect(
|
||||
resolvePath('standard/you/are/here/README.md', '../../other-note.md')
|
||||
).toEqual('standard/you/other-note.md')
|
||||
resolvePath("standard/you/are/here/README.md", "../../other-note.md")
|
||||
).toEqual("standard/you/other-note.md")
|
||||
|
||||
expect(
|
||||
resolvePath('standard/you/are/here/README.md', './../../other-note.md')
|
||||
).toEqual('standard/you/other-note.md')
|
||||
resolvePath("standard/you/are/here/README.md", "./../../other-note.md")
|
||||
).toEqual("standard/you/other-note.md")
|
||||
|
||||
expect(
|
||||
resolvePath('standard/you/are/here/README.md', './../../../other-note.md')
|
||||
).toEqual('standard/other-note.md')
|
||||
resolvePath("standard/you/are/here/README.md", "./../../../other-note.md")
|
||||
).toEqual("standard/other-note.md")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
const sanitizePath = (path: string) => {
|
||||
if (path.startsWith('./')) {
|
||||
return decodeURIComponent(path.replace('./', ''))
|
||||
if (path.startsWith("./")) {
|
||||
return decodeURIComponent(path.replace("./", ""))
|
||||
}
|
||||
return decodeURIComponent(path)
|
||||
}
|
||||
|
||||
const removeNoteFilename = (pathNote: string) => {
|
||||
const path = pathNote.split('/')
|
||||
const path = pathNote.split("/")
|
||||
path.pop()
|
||||
|
||||
return sanitizePath(path.join('/'))
|
||||
return sanitizePath(path.join("/"))
|
||||
}
|
||||
|
||||
export const resolvePath = (
|
||||
@@ -19,11 +19,11 @@ export const resolvePath = (
|
||||
let currentAbsolutePath = removeNoteFilename(currentAbsolutePathNote)
|
||||
pathToResolve = sanitizePath(pathToResolve)
|
||||
|
||||
while (pathToResolve.startsWith('../')) {
|
||||
const adjustedAbsolutePath = currentAbsolutePath.split('/')
|
||||
while (pathToResolve.startsWith("../")) {
|
||||
const adjustedAbsolutePath = currentAbsolutePath.split("/")
|
||||
adjustedAbsolutePath.pop()
|
||||
currentAbsolutePath = adjustedAbsolutePath.join('/')
|
||||
pathToResolve = pathToResolve.replace('../', '')
|
||||
currentAbsolutePath = adjustedAbsolutePath.join("/")
|
||||
pathToResolve = pathToResolve.replace("../", "")
|
||||
}
|
||||
|
||||
return currentAbsolutePath
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
getCachedMainReadme,
|
||||
getFiles,
|
||||
getMainReadme,
|
||||
getUserSettingsContent,
|
||||
getUserSettingsContent
|
||||
} from "@/modules/repo/services/repo"
|
||||
import { refreshToken } from "@/modules/user/service/signIn"
|
||||
|
||||
@@ -29,7 +29,7 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
|
||||
files: [],
|
||||
readme: undefined,
|
||||
userSettings: undefined,
|
||||
needToLogin: false,
|
||||
needToLogin: false
|
||||
}),
|
||||
actions: {
|
||||
async setUserRepo(user: string, repo: string) {
|
||||
@@ -38,7 +38,7 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
|
||||
|
||||
const savedRepoId = data.generateId(DataType.SavedRepo, `${user}-${repo}`)
|
||||
const cachedSavedRepo = await data.get<DataType.SavedRepo, SavedRepo>(
|
||||
savedRepoId,
|
||||
savedRepoId
|
||||
)
|
||||
|
||||
if (cachedSavedRepo) {
|
||||
@@ -68,14 +68,14 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
|
||||
$type: DataType.SavedRepo,
|
||||
repo,
|
||||
user,
|
||||
files,
|
||||
files
|
||||
})
|
||||
this.files = files
|
||||
return getUserSettingsContent(user, repo, files)
|
||||
})
|
||||
.then((userSettings) => {
|
||||
const chosenFontFamily = userSettings?.fontFamilies?.find(
|
||||
(font) => font === this.userSettings?.chosenFontFamily,
|
||||
(font) => font === this.userSettings?.chosenFontFamily
|
||||
)
|
||||
? this.userSettings?.chosenFontFamily
|
||||
: userSettings?.fontFamily
|
||||
@@ -94,7 +94,7 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
|
||||
|
||||
data.update<DataType.UserSettings, UserSettings>({
|
||||
...this.userSettings,
|
||||
_id: userSettingsId,
|
||||
_id: userSettingsId
|
||||
})
|
||||
})
|
||||
|
||||
@@ -116,7 +116,7 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
|
||||
|
||||
const savedRepoId = data.generateId(
|
||||
DataType.SavedRepo,
|
||||
`${this.user}-${this.repo}`,
|
||||
`${this.user}-${this.repo}`
|
||||
)
|
||||
const newFiles = [...this.files.filter((f) => f.sha !== file.sha), file]
|
||||
data.update<DataType.SavedRepo, SavedRepo>({
|
||||
@@ -124,7 +124,7 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
|
||||
$type: DataType.SavedRepo,
|
||||
repo: this.repo,
|
||||
user: this.user,
|
||||
files: newFiles,
|
||||
files: newFiles
|
||||
})
|
||||
this.files = newFiles
|
||||
},
|
||||
@@ -147,7 +147,7 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
|
||||
const userSettingsId = `UserSetting-${this.user}-${this.repo}`
|
||||
data.update<DataType.UserSettings, UserSettings>({
|
||||
...this.userSettings,
|
||||
_id: userSettingsId,
|
||||
_id: userSettingsId
|
||||
})
|
||||
},
|
||||
setFontSize(fontSize: string) {
|
||||
@@ -159,8 +159,8 @@ export const useUserRepoStore = defineStore("USER_REPO_STATE", {
|
||||
const userSettingsId = `UserSetting-${this.user}-${this.repo}`
|
||||
data.update<DataType.UserSettings, UserSettings>({
|
||||
...this.userSettings,
|
||||
_id: userSettingsId,
|
||||
_id: userSettingsId
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -4,5 +4,5 @@ export interface GithubToken {
|
||||
refresh_token: string
|
||||
refresh_token_expires_in: number
|
||||
scope: string
|
||||
token_type: 'bearer'
|
||||
token_type: "bearer"
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ const AUTHENTICATION_SERVER = "https://api.remanso.space/auth/github"
|
||||
const personalTokenId = "token"
|
||||
|
||||
export const signIn = async (
|
||||
code: string,
|
||||
code: string
|
||||
): Promise<GithubToken | GithubTokenError> => {
|
||||
const authenticationServerURL = new URL(AUTHENTICATION_SERVER)
|
||||
authenticationServerURL.searchParams.set("code", code)
|
||||
@@ -84,12 +84,12 @@ export const saveAccessToken = async (githubToken: GithubToken) => {
|
||||
|
||||
const expirationDate = addSeconds(
|
||||
new Date(),
|
||||
githubToken.expires_in,
|
||||
githubToken.expires_in
|
||||
).toISOString()
|
||||
|
||||
const refreshTokenExpirationDate = addSeconds(
|
||||
new Date(),
|
||||
githubToken.refresh_token_expires_in,
|
||||
githubToken.refresh_token_expires_in
|
||||
).toISOString()
|
||||
|
||||
const accessToken: GithubAccessToken = {
|
||||
@@ -102,11 +102,11 @@ export const saveAccessToken = async (githubToken: GithubToken) => {
|
||||
refreshToken: githubToken.refresh_token,
|
||||
refreshTokenExpiresIn: githubToken.refresh_token_expires_in,
|
||||
refreshTokenExpirationDate,
|
||||
username: "",
|
||||
username: ""
|
||||
}
|
||||
|
||||
const octokit = new Octokit({
|
||||
auth: accessToken?.token,
|
||||
auth: accessToken?.token
|
||||
})
|
||||
|
||||
const user = await octokit.request("GET /user")
|
||||
|
||||
@@ -7,98 +7,102 @@ const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/repo-list",
|
||||
name: "RepoList",
|
||||
component: () => import("@/views/RepoList.vue"),
|
||||
component: () => import("@/views/RepoList.vue")
|
||||
},
|
||||
{
|
||||
path: "/:user/:repo",
|
||||
name: "FluxNoteView",
|
||||
props: true,
|
||||
component: () => import("@/views/FluxNoteView.vue"),
|
||||
component: () => import("@/views/FluxNoteView.vue")
|
||||
},
|
||||
{
|
||||
path: "/tiboudenote",
|
||||
name: "PublicNoteListView",
|
||||
component: () => import("@/views/PublicNoteListView.vue"),
|
||||
component: () => import("@/views/PublicNoteListView.vue")
|
||||
},
|
||||
{
|
||||
path: "/pub",
|
||||
name: "PublicNoteListView",
|
||||
component: () => import("@/views/PublicNoteListView.vue"),
|
||||
component: () => import("@/views/PublicNoteListView.vue")
|
||||
},
|
||||
{
|
||||
path: "/pub/:shortDid",
|
||||
name: "PublicNoteListByDidView",
|
||||
props: true,
|
||||
component: () => import("@/views/PublicNoteListByDidView.vue"),
|
||||
component: () => import("@/views/PublicNoteListByDidView.vue")
|
||||
},
|
||||
{
|
||||
path: "/pub/:shortDid/:rkey/:slug?",
|
||||
name: "PublicNoteView",
|
||||
props: true,
|
||||
component: () => import("@/views/PublicNoteView.vue"),
|
||||
component: () => import("@/views/PublicNoteView.vue")
|
||||
},
|
||||
{
|
||||
path: "/:user/:repo/inbox",
|
||||
name: "FleetingNotes",
|
||||
props: true,
|
||||
component: () => import("@/views/FleetingNotes.vue"),
|
||||
component: () => import("@/views/FleetingNotes.vue")
|
||||
},
|
||||
{
|
||||
path: "/:user/:repo/draft",
|
||||
name: "DraftNotes",
|
||||
props: true,
|
||||
component: () => import("@/views/DraftNotes.vue"),
|
||||
component: () => import("@/views/DraftNotes.vue")
|
||||
},
|
||||
{
|
||||
path: "/:user/:repo/todo",
|
||||
name: "TodoNotes",
|
||||
props: true,
|
||||
component: () => import("@/views/TodoNotes.vue"),
|
||||
component: () => import("@/views/TodoNotes.vue")
|
||||
},
|
||||
{
|
||||
path: "/:user/:repo/history",
|
||||
name: "HistoricNotes",
|
||||
props: true,
|
||||
component: () => import("@/views/HistoricNotes.vue"),
|
||||
component: () => import("@/views/HistoricNotes.vue")
|
||||
},
|
||||
{
|
||||
path: "/:user/:repo/spaced-repetition",
|
||||
name: "SpacedRepetitionCard",
|
||||
props: true,
|
||||
component: () => import("@/views/SpacedRepetitionCard.vue"),
|
||||
component: () => import("@/views/SpacedRepetitionCard.vue")
|
||||
},
|
||||
{
|
||||
path: "/:user/:repo/need-review-cards",
|
||||
name: "NeedReviewCards",
|
||||
props: true,
|
||||
component: () => import("@/views/NeedReviewCards.vue"),
|
||||
component: () => import("@/views/NeedReviewCards.vue")
|
||||
},
|
||||
{
|
||||
path: "/about",
|
||||
name: "About",
|
||||
component: () => import("@/views/AboutApp.vue"),
|
||||
component: () => import("@/views/AboutApp.vue")
|
||||
},
|
||||
{
|
||||
path: "/",
|
||||
name: "Home",
|
||||
component: Home,
|
||||
component: Home
|
||||
},
|
||||
{
|
||||
path: "/:catchAll(.*)",
|
||||
name: "SpaceCowboy",
|
||||
component: () => import("@/views/SpaceCowboy.vue"),
|
||||
},
|
||||
component: () => import("@/views/SpaceCowboy.vue")
|
||||
}
|
||||
]
|
||||
|
||||
export const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes,
|
||||
routes
|
||||
})
|
||||
|
||||
router.beforeEach(() => {
|
||||
if (!("startViewTransition" in document)) return
|
||||
return new Promise<void>((resolve) => {
|
||||
;(document as Document & { startViewTransition: (cb: () => Promise<void>) => void }).startViewTransition(async () => {
|
||||
;(
|
||||
document as Document & {
|
||||
startViewTransition: (cb: () => Promise<void>) => void
|
||||
}
|
||||
).startViewTransition(async () => {
|
||||
resolve()
|
||||
await nextTick()
|
||||
})
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
// Update these values to change the light and dark themes
|
||||
|
||||
export const themeConfig = {
|
||||
light: 'garden',
|
||||
dark: 'dim',
|
||||
light: "garden",
|
||||
dark: "dim"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
export const decodeBase64ToUTF8 = (content: string): string => {
|
||||
return decodeURIComponent(
|
||||
atob(content)
|
||||
.split('')
|
||||
.map((char) => `%${('00' + char.charCodeAt(0).toString(16)).slice(-2)}`)
|
||||
.join('')
|
||||
.split("")
|
||||
.map((char) => `%${("00" + char.charCodeAt(0).toString(16)).slice(-2)}`)
|
||||
.join("")
|
||||
)
|
||||
}
|
||||
export const encodeUTF8ToBase64 = (content: string): string => {
|
||||
|
||||
@@ -6,7 +6,7 @@ export const displayLanguage = (langCode?: string): string | null => {
|
||||
try {
|
||||
const locale = navigator.language ?? langCode
|
||||
const display = new Intl.DisplayNames([locale], {
|
||||
type: "language",
|
||||
type: "language"
|
||||
})
|
||||
|
||||
return display.of(langCode) ?? null
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// We can only detect video/audio files from the extension in the URL.
|
||||
// We ignore MP1 and MP2 (not in active use) and default to video for ambiguous
|
||||
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import MarkdownIt from "markdown-it"
|
||||
|
||||
// extensions (MPG, MP4)
|
||||
const validAudioExtensions = ['aac', 'm4a', 'mp3', 'oga', 'ogg', 'wav']
|
||||
const validVideoExtensions = ['mp4', 'm4v', 'ogv', 'webm', 'mpg', 'mpeg']
|
||||
const validAudioExtensions = ["aac", "m4a", "mp3", "oga", "ogg", "wav"]
|
||||
const validVideoExtensions = ["mp4", "m4v", "ogv", "webm", "mpg", "mpeg"]
|
||||
|
||||
/**
|
||||
* @property {Object} messages
|
||||
@@ -19,13 +19,13 @@ const validVideoExtensions = ['mp4', 'm4v', 'ogv', 'webm', 'mpg', 'mpeg']
|
||||
*/
|
||||
let messages: { [key: string]: any } = {
|
||||
en: {
|
||||
'html5 video not supported':
|
||||
'Your browser does not support playing HTML5 video.',
|
||||
'html5 audio not supported':
|
||||
'Your browser does not support playing HTML5 audio.',
|
||||
'html5 media fallback link':
|
||||
"html5 video not supported":
|
||||
"Your browser does not support playing HTML5 video.",
|
||||
"html5 audio not supported":
|
||||
"Your browser does not support playing HTML5 audio.",
|
||||
"html5 media fallback link":
|
||||
'You can <a href="%s" download>download the file</a> instead.',
|
||||
'html5 media description': 'Here is a description of the content: %s'
|
||||
"html5 media description": "Here is a description of the content: %s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,18 +37,18 @@ let translate = (
|
||||
// Revert back to English default if no message object, or no translation
|
||||
// for this language
|
||||
if (!messages[language] || !messages[language][messageKey]) {
|
||||
language = 'en'
|
||||
language = "en"
|
||||
}
|
||||
|
||||
if (!messages[language]) {
|
||||
return ''
|
||||
return ""
|
||||
}
|
||||
|
||||
let message = messages[language][messageKey] || ''
|
||||
let message = messages[language][messageKey] || ""
|
||||
|
||||
if (messageParams)
|
||||
for (const param of messageParams) {
|
||||
message = message.replace('%s', param)
|
||||
message = message.replace("%s", param)
|
||||
}
|
||||
|
||||
return message
|
||||
@@ -96,7 +96,7 @@ function tokenizeImagesAndMedia(
|
||||
}
|
||||
): boolean {
|
||||
let attrs, code, label, pos, ref, res, title, tokens: never[], start
|
||||
let href = ''
|
||||
let href = ""
|
||||
const oldPos = state.pos
|
||||
const max = state.posMax
|
||||
|
||||
@@ -140,7 +140,7 @@ function tokenizeImagesAndMedia(
|
||||
if (state.md.validateLink(href)) {
|
||||
pos = res.pos
|
||||
} else {
|
||||
href = ''
|
||||
href = ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ function tokenizeImagesAndMedia(
|
||||
if (!md.utils.isSpace(code) && code !== 0x0a) break
|
||||
}
|
||||
} else {
|
||||
title = ''
|
||||
title = ""
|
||||
}
|
||||
|
||||
if (pos >= max || state.src.charCodeAt(pos) !== 0x29) {
|
||||
@@ -179,7 +179,7 @@ function tokenizeImagesAndMedia(
|
||||
//
|
||||
// Link reference
|
||||
//
|
||||
if (typeof state.env.references === 'undefined') return false
|
||||
if (typeof state.env.references === "undefined") return false
|
||||
|
||||
if (pos < max && state.src.charCodeAt(pos) === 0x5b) {
|
||||
// Bracket: [
|
||||
@@ -219,15 +219,15 @@ function tokenizeImagesAndMedia(
|
||||
state.md.inline.parse(content, state.md, state.env, (tokens = []))
|
||||
|
||||
const mediaType = guessMediaType(href)
|
||||
const tag = mediaType == 'image' ? 'img' : mediaType
|
||||
const tag = mediaType == "image" ? "img" : mediaType
|
||||
|
||||
const token = state.push(mediaType, tag, 0)
|
||||
token.attrs = attrs = [['src', href]]
|
||||
if (mediaType == 'image') attrs.push(['alt', ''])
|
||||
token.attrs = attrs = [["src", href]]
|
||||
if (mediaType == "image") attrs.push(["alt", ""])
|
||||
token.children = tokens
|
||||
token.content = content
|
||||
|
||||
if (title) attrs.push(['title', title])
|
||||
if (title) attrs.push(["title", title])
|
||||
|
||||
state.pos = pos
|
||||
state.posMax = max
|
||||
@@ -247,13 +247,13 @@ function tokenizeImagesAndMedia(
|
||||
*/
|
||||
function guessMediaType(url: string): string {
|
||||
const extensionMatch = url.match(/\.([^/.]+)$/)
|
||||
if (extensionMatch === null) return 'image'
|
||||
if (extensionMatch === null) return "image"
|
||||
const extension = extensionMatch[1]
|
||||
if (validAudioExtensions.indexOf(extension.toLowerCase()) != -1)
|
||||
return 'audio'
|
||||
return "audio"
|
||||
else if (validVideoExtensions.indexOf(extension.toLowerCase()) != -1)
|
||||
return 'video'
|
||||
else return 'image'
|
||||
return "video"
|
||||
else return "image"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,37 +283,37 @@ function renderMedia(
|
||||
const token = tokens[idx]
|
||||
const type = token.type
|
||||
|
||||
if (!token.attrs || (type !== 'video' && type !== 'audio')) {
|
||||
return ''
|
||||
if (!token.attrs || (type !== "video" && type !== "audio")) {
|
||||
return ""
|
||||
}
|
||||
|
||||
let attrs = options.html5Media[`${type}Attrs`].trim()
|
||||
if (attrs) {
|
||||
attrs = ' ' + attrs
|
||||
attrs = " " + attrs
|
||||
}
|
||||
|
||||
// We'll always have a URL for non-image media: they are detected by URL
|
||||
const url = token.attrs[token.attrIndex('src')][1]
|
||||
const url = token.attrs[token.attrIndex("src")][1]
|
||||
|
||||
// Title is set like this: 
|
||||
const title =
|
||||
token.attrIndex('title') != -1
|
||||
token.attrIndex("title") != -1
|
||||
? ` title="${md.utils.escapeHtml(
|
||||
token.attrs[token.attrIndex('title')][1]
|
||||
token.attrs[token.attrIndex("title")][1]
|
||||
)}"`
|
||||
: ''
|
||||
: ""
|
||||
|
||||
const fallbackText =
|
||||
translate(env.language, `html5 ${type} not supported`) +
|
||||
'\n' +
|
||||
translate(env.language, 'html5 media fallback link', [url])
|
||||
"\n" +
|
||||
translate(env.language, "html5 media fallback link", [url])
|
||||
|
||||
const description = token.content
|
||||
? '\n' +
|
||||
translate(env.language, 'html5 media description', [
|
||||
? "\n" +
|
||||
translate(env.language, "html5 media description", [
|
||||
md.utils.escapeHtml(token.content)
|
||||
])
|
||||
: ''
|
||||
: ""
|
||||
|
||||
return (
|
||||
`<${type} src="${url}"${title}${attrs}>\n` +
|
||||
@@ -369,7 +369,7 @@ export const html5Media = (
|
||||
? options.audioAttrs
|
||||
: 'controls class="html5-audio-player"'
|
||||
|
||||
md.inline.ruler.at('image', (tokens: any, silent: any) =>
|
||||
md.inline.ruler.at("image", (tokens: any, silent: any) =>
|
||||
tokenizeImagesAndMedia(tokens, silent, md)
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import MarkdownIt, { PluginSimple } from 'markdown-it'
|
||||
import MarkdownIt, { PluginSimple } from "markdown-it"
|
||||
|
||||
let counter = 0
|
||||
|
||||
@@ -6,14 +6,14 @@ export const markdownItPlugin = (
|
||||
regex: RegExp,
|
||||
replacer: (matches: RegExpExecArray[]) => string
|
||||
): PluginSimple => {
|
||||
const id = 'regexp-' + counter
|
||||
const id = "regexp-" + counter
|
||||
counter++
|
||||
const flags =
|
||||
(regex.global ? 'g' : '') +
|
||||
(regex.multiline ? 'm' : '') +
|
||||
(regex.ignoreCase ? 'i' : '')
|
||||
(regex.global ? "g" : "") +
|
||||
(regex.multiline ? "m" : "") +
|
||||
(regex.ignoreCase ? "i" : "")
|
||||
|
||||
const regexp = RegExp('^' + regex.source, flags)
|
||||
const regexp = RegExp("^" + regex.source, flags)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const parse = (state: any, silent: boolean): boolean => {
|
||||
@@ -31,7 +31,7 @@ export const markdownItPlugin = (
|
||||
return true
|
||||
}
|
||||
|
||||
const token = state.push(id, '', 0)
|
||||
const token = state.push(id, "", 0)
|
||||
token.meta = { match }
|
||||
|
||||
return true
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { markdownItPlugin } from "./markdown-it-regexp"
|
||||
|
||||
// Matches :icon-name: where icon-name is letters, digits, hyphens
|
||||
export const markdownItTablerIcons = markdownItPlugin(
|
||||
/:([\w-]+):/,
|
||||
(match) => {
|
||||
const name = match[1]
|
||||
return `<i class="ti ti-${name}"></i>`
|
||||
},
|
||||
)
|
||||
export const markdownItTablerIcons = markdownItPlugin(/:([\w-]+):/, (match) => {
|
||||
const name = match[1]
|
||||
return `<i class="ti ti-${name}"></i>`
|
||||
})
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
export const filenameToNoteTitle = (title: string) =>
|
||||
title.replaceAll('/', ' / ').replaceAll('-', ' ')
|
||||
title.replaceAll("/", " / ").replaceAll("-", " ")
|
||||
|
||||
export const pathToNotePathTitle = (path: string) => {
|
||||
const fileNames = path.split('.')
|
||||
const fileNames = path.split(".")
|
||||
|
||||
fileNames.pop()
|
||||
return fileNames
|
||||
.join('.')
|
||||
.split('/')
|
||||
.filter((path) => !path.includes('README'))
|
||||
.join('/')
|
||||
.replaceAll('-', ' ')
|
||||
.join(".")
|
||||
.split("/")
|
||||
.filter((path) => !path.includes("README"))
|
||||
.join("/")
|
||||
.replaceAll("-", " ")
|
||||
}
|
||||
|
||||
export const pathToNoteTitle = (notePathTitle: string) => {
|
||||
return pathToNotePathTitle(notePathTitle).split('/').pop()?.trim() ?? ''
|
||||
return pathToNotePathTitle(notePathTitle).split("/").pop()?.trim() ?? ""
|
||||
}
|
||||
|
||||
@@ -4,23 +4,23 @@ const notif = new Notyf({
|
||||
types: [
|
||||
{
|
||||
className: "alert alert-success",
|
||||
type: "confirm",
|
||||
type: "confirm"
|
||||
},
|
||||
{
|
||||
className: "alert alert-error",
|
||||
type: "error",
|
||||
},
|
||||
],
|
||||
type: "error"
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
export const confirmMessage = (message: string) =>
|
||||
notif.open({
|
||||
type: "confirm",
|
||||
message,
|
||||
message
|
||||
})
|
||||
|
||||
export const errorMessage = (message: string) =>
|
||||
notif.open({
|
||||
type: "error",
|
||||
message,
|
||||
message
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { format } from "date-fns"
|
||||
import { computed, ref, watch } from "vue"
|
||||
|
||||
import FluxNote from "@/components/FluxNote.vue"
|
||||
import { useEditionMode } from "@/hooks/useEditionMode"
|
||||
import { useGitHubContent } from "@/hooks/useGitHubContent.hook"
|
||||
@@ -70,7 +71,7 @@ const handleYouTube = async () => {
|
||||
|
||||
const { createFile } = useGitHubContent({
|
||||
repo: repo.value,
|
||||
user: user.value,
|
||||
user: user.value
|
||||
})
|
||||
|
||||
const hasTodayNote = computed(() => content.value.includes(today))
|
||||
@@ -83,7 +84,7 @@ watch(mode, async (newMode) => {
|
||||
|
||||
const newSha = await createFile({
|
||||
content,
|
||||
path: newContentPath,
|
||||
path: newContentPath
|
||||
})
|
||||
|
||||
if (!newSha) {
|
||||
@@ -94,7 +95,7 @@ watch(mode, async (newMode) => {
|
||||
const { saveCacheNote } = prepareNoteCache(newSha, newContentPath)
|
||||
await saveCacheNote(encodeUTF8ToBase64(content), {
|
||||
editedSha: newSha,
|
||||
path: newContentPath,
|
||||
path: newContentPath
|
||||
})
|
||||
|
||||
addStackedNote("", newSha)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { computed } from "vue"
|
||||
|
||||
import FluxNote from '@/components/FluxNote.vue'
|
||||
import { useComputeBacklinks } from '@/hooks/useComputeBacklinks.hook'
|
||||
import FluxNote from "@/components/FluxNote.vue"
|
||||
import { useComputeBacklinks } from "@/hooks/useComputeBacklinks.hook"
|
||||
|
||||
useComputeBacklinks()
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, ref } from 'vue'
|
||||
import { defineAsyncComponent, ref } from "vue"
|
||||
|
||||
import { useNotes } from '@/modules/note/hooks/useNotes'
|
||||
import { useNotes } from "@/modules/note/hooks/useNotes"
|
||||
|
||||
const devMode = ref(import.meta.env.DEV)
|
||||
const FluxNote = defineAsyncComponent(() => import('@/components/FluxNote.vue'))
|
||||
const FluxNote = defineAsyncComponent(() => import("@/components/FluxNote.vue"))
|
||||
|
||||
defineProps<{ user: string; repo: string }>()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import AuthorizeUser from '@/components/AuthorizeUser.vue'
|
||||
import WelcomeWorld from '@/components/WelcomeWorld.vue'
|
||||
import AuthorizeUser from "@/components/AuthorizeUser.vue"
|
||||
import WelcomeWorld from "@/components/WelcomeWorld.vue"
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { computed } from "vue"
|
||||
|
||||
import FluxNote from '@/components/FluxNote.vue'
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { useNeedReviewCards } from '@/modules/card/hooks/useNeedReviewCards'
|
||||
import FluxNote from "@/components/FluxNote.vue"
|
||||
import { DataType } from "@/data/DataType.enum"
|
||||
import { useNeedReviewCards } from "@/modules/card/hooks/useNeedReviewCards"
|
||||
|
||||
defineProps<{
|
||||
user: string
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { computedAsync } from "@vueuse/core"
|
||||
import { computed } from "vue"
|
||||
|
||||
import HomeButton from "@/components/HomeButton.vue"
|
||||
import PublicNoteList from "@/components/PublicNoteList.vue"
|
||||
import SkeletonLoader from "@/components/SkeletonLoader.vue"
|
||||
import { usePublicNoteList } from "@/hooks/usePublicNoteList.hook"
|
||||
import { getAuthor } from "@/modules/atproto/getAuthor"
|
||||
import { fromShortDid } from "@/modules/atproto/shortDid"
|
||||
import { computedAsync } from "@vueuse/core"
|
||||
import { computed } from "vue"
|
||||
|
||||
const props = defineProps<{ shortDid: string }>()
|
||||
const did = computed(() => fromShortDid(props.shortDid))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user