Merge branch 'main' of ssh://git.apoena.dev:22222/julien/remanso
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
# Remanso
|
# Remanso
|
||||||
|
|
||||||
|
Welcome to Remanso!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
[Remanso website](https://remanso.space)
|
[Remanso website](https://remanso.space)
|
||||||
|
|||||||
2
nixpacks.toml
Normal file
2
nixpacks.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[phases.setup]
|
||||||
|
nixPkgs = ["nodejs_24", "pnpm"]
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { PublicNoteListItem } from "@/modules/note/models/Note"
|
import { PublicNoteListItem } from "@/modules/note/models/Note"
|
||||||
|
import { toShortDid } from "@/modules/atproto/shortDid"
|
||||||
import { slugify } from "@/utils/slugify"
|
import { slugify } from "@/utils/slugify"
|
||||||
import { vInfiniteScroll } from "@vueuse/components"
|
import { vInfiniteScroll } from "@vueuse/components"
|
||||||
|
|
||||||
@@ -25,7 +26,7 @@ defineSlots<{
|
|||||||
:to="{
|
:to="{
|
||||||
name: 'PublicNoteView',
|
name: 'PublicNoteView',
|
||||||
params: {
|
params: {
|
||||||
did: note.did,
|
shortDid: toShortDid(note.did),
|
||||||
rkey: note.rkey,
|
rkey: note.rkey,
|
||||||
slug: slugify(note.title),
|
slug: slugify(note.title),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { computedAsync } from "@vueuse/core"
|
|||||||
import { getUrl } from "@/modules/atproto/getUrl"
|
import { getUrl } from "@/modules/atproto/getUrl"
|
||||||
import { withATProtoImages } from "@/modules/atproto/withATProtoImages"
|
import { withATProtoImages } from "@/modules/atproto/withATProtoImages"
|
||||||
import { getAuthor } from "@/modules/atproto/getAuthor"
|
import { getAuthor } from "@/modules/atproto/getAuthor"
|
||||||
|
import { fromShortDid } from "@/modules/atproto/shortDid"
|
||||||
import { PublicNoteRecord } from "@/modules/atproto/publicNote.types"
|
import { PublicNoteRecord } from "@/modules/atproto/publicNote.types"
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -17,7 +18,7 @@ const props = defineProps<{
|
|||||||
}>()
|
}>()
|
||||||
|
|
||||||
const didrkey = computed(() => props.didrkey)
|
const didrkey = computed(() => props.didrkey)
|
||||||
const did = computed(() => props.didrkey.split("-")[0])
|
const did = computed(() => fromShortDid(props.didrkey.split("-")[0]))
|
||||||
const rkey = computed(() => props.didrkey.split("-")[1])
|
const rkey = computed(() => props.didrkey.split("-")[1])
|
||||||
const classNameId = computed(() => didrkey.value.replaceAll(":", "-"))
|
const classNameId = computed(() => didrkey.value.replaceAll(":", "-"))
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { ComputedRef, onUnmounted, Ref, toValue } from "vue"
|
|||||||
import { isExternalLink } from "@/utils/link"
|
import { isExternalLink } from "@/utils/link"
|
||||||
import { useRouteQueryStackedNotes } from "@/hooks/useRouteQueryStackedNotes.hook"
|
import { useRouteQueryStackedNotes } from "@/hooks/useRouteQueryStackedNotes.hook"
|
||||||
import { parseAtUri } from "@/modules/atproto/parseAtUri"
|
import { parseAtUri } from "@/modules/atproto/parseAtUri"
|
||||||
|
import { toShortDid } from "@/modules/atproto/shortDid"
|
||||||
import { router } from "@/router/router"
|
import { router } from "@/router/router"
|
||||||
|
|
||||||
export const useATProtoLinks = (
|
export const useATProtoLinks = (
|
||||||
@@ -35,25 +36,25 @@ export const useATProtoLinks = (
|
|||||||
href.replace(window.location.origin, ""),
|
href.replace(window.location.origin, ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!params.did || !params.rkey) {
|
if (!params.shortDid || !params.rkey) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const noteId = params.slug
|
const noteId = params.slug
|
||||||
? `${params.did}-${params.rkey}-${params.slug}`
|
? `${params.shortDid}-${params.rkey}-${params.slug}`
|
||||||
: `${params.did}-${params.rkey}`
|
: `${params.shortDid}-${params.rkey}`
|
||||||
|
|
||||||
addStackedNote(
|
addStackedNote(
|
||||||
toValue(currentAtUri) ?? "",
|
toValue(currentAtUri) ?? "",
|
||||||
noteId,
|
noteId,
|
||||||
`${params.did}-${params.rkey}`,
|
`${params.shortDid}-${params.rkey}`,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (href.startsWith("at://")) {
|
if (href.startsWith("at://")) {
|
||||||
const { did, rkey } = parseAtUri(href)
|
const { did, rkey } = parseAtUri(href)
|
||||||
const noteId = `${did}-${rkey}`
|
const noteId = `${toShortDid(did)}-${rkey}`
|
||||||
|
|
||||||
addStackedNote(toValue(currentAtUri) ?? "", noteId)
|
addStackedNote(toValue(currentAtUri) ?? "", noteId)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,16 @@ import { PublicNoteListItem } from "@/modules/note/models/Note"
|
|||||||
import { computedAsync } from "@vueuse/core"
|
import { computedAsync } from "@vueuse/core"
|
||||||
import { computed, ref, Ref, watch } from "vue"
|
import { computed, ref, Ref, watch } from "vue"
|
||||||
|
|
||||||
export function useFollowingNoteList(dids: Ref<Set<string>>, enabled: Ref<boolean>) {
|
export function useFollowingNoteList(
|
||||||
|
dids: Ref<Set<string>>,
|
||||||
|
enabled: Ref<boolean>,
|
||||||
|
) {
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
const notes = ref<PublicNoteListItem[]>([])
|
const notes = ref<PublicNoteListItem[]>([])
|
||||||
const cursor = ref<string | null | undefined>(null)
|
const cursor = ref<string | null | undefined>(null)
|
||||||
const canLoadMore = computed(() => dids.value.size > 0 && cursor.value !== undefined)
|
const canLoadMore = computed(
|
||||||
|
() => dids.value.size > 0 && cursor.value !== undefined,
|
||||||
|
)
|
||||||
|
|
||||||
const onLoadMore = async () => {
|
const onLoadMore = async () => {
|
||||||
if (isLoading.value) return
|
if (isLoading.value) return
|
||||||
@@ -24,13 +29,14 @@ export function useFollowingNoteList(dids: Ref<Set<string>>, enabled: Ref<boolea
|
|||||||
body.cursor = cursor.value
|
body.cursor = cursor.value
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch("https://api.litenote.li212.fr/notes/feed", {
|
const response = await fetch("https://api.remanso.space/notes/feed", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
})
|
})
|
||||||
|
|
||||||
const data: { notes: PublicNoteListItem[]; cursor?: string } = await response.json()
|
const data: { notes: PublicNoteListItem[]; cursor?: string } =
|
||||||
|
await response.json()
|
||||||
|
|
||||||
notes.value.push(...data.notes)
|
notes.value.push(...data.notes)
|
||||||
cursor.value = data.cursor
|
cursor.value = data.cursor
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function usePublicNoteList(options?: UsePublicNoteListOptions) {
|
|||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
|
|
||||||
const path = options?.did?.value ? `/${options.did.value}/notes` : "/notes"
|
const path = options?.did?.value ? `/${options.did.value}/notes` : "/notes"
|
||||||
const noteAPI = new URL(path, "https://api.litenote.li212.fr")
|
const noteAPI = new URL(path, "https://api.remanso.space")
|
||||||
|
|
||||||
if (cursor.value) {
|
if (cursor.value) {
|
||||||
noteAPI.searchParams.set("cursor", cursor.value)
|
noteAPI.searchParams.set("cursor", cursor.value)
|
||||||
|
|||||||
8
src/modules/atproto/shortDid.ts
Normal file
8
src/modules/atproto/shortDid.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export const toShortDid = (did: string) => did.replace(/^did:(plc:)?/, "")
|
||||||
|
// did:plc:xxx → xxx, did:web:x → web:x
|
||||||
|
|
||||||
|
export const fromShortDid = (shortDid: string) => {
|
||||||
|
if (shortDid.startsWith("did:")) return shortDid
|
||||||
|
return shortDid.includes(":") ? `did:${shortDid}` : `did:plc:${shortDid}`
|
||||||
|
}
|
||||||
|
// xxx → did:plc:xxx, web:x → did:web:x, did:plc:xxx → did:plc:xxx (passthrough)
|
||||||
@@ -60,5 +60,5 @@ export const noteRouter = contract.router({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const client = initQueryClient(noteRouter, {
|
export const client = initQueryClient(noteRouter, {
|
||||||
baseUrl: "https://api.litenote.li212.fr",
|
baseUrl: "https://api.remanso.space",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
component: () => import("@/views/PublicNoteListView.vue"),
|
component: () => import("@/views/PublicNoteListView.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/pub/:did",
|
path: "/pub/:shortDid",
|
||||||
name: "PublicNoteListByDidView",
|
name: "PublicNoteListByDidView",
|
||||||
props: true,
|
props: true,
|
||||||
component: () => import("@/views/PublicNoteListByDidView.vue"),
|
component: () => import("@/views/PublicNoteListByDidView.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/pub/:did/:rkey/:slug?",
|
path: "/pub/:shortDid/:rkey/:slug?",
|
||||||
name: "PublicNoteView",
|
name: "PublicNoteView",
|
||||||
props: true,
|
props: true,
|
||||||
component: () => import("@/views/PublicNoteView.vue"),
|
component: () => import("@/views/PublicNoteView.vue"),
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ import HomeButton from "@/components/HomeButton.vue"
|
|||||||
import PublicNoteList from "@/components/PublicNoteList.vue"
|
import PublicNoteList from "@/components/PublicNoteList.vue"
|
||||||
import { usePublicNoteList } from "@/hooks/usePublicNoteList.hook"
|
import { usePublicNoteList } from "@/hooks/usePublicNoteList.hook"
|
||||||
import { getAuthor } from "@/modules/atproto/getAuthor"
|
import { getAuthor } from "@/modules/atproto/getAuthor"
|
||||||
|
import { fromShortDid } from "@/modules/atproto/shortDid"
|
||||||
import { computedAsync } from "@vueuse/core"
|
import { computedAsync } from "@vueuse/core"
|
||||||
import { computed } from "vue"
|
import { computed } from "vue"
|
||||||
|
|
||||||
const props = defineProps<{ did: string }>()
|
const props = defineProps<{ shortDid: string }>()
|
||||||
const did = computed(() => props.did)
|
const did = computed(() => fromShortDid(props.shortDid))
|
||||||
|
|
||||||
const { notes, isLoading, canLoadMore, onLoadMore } = usePublicNoteList({ did })
|
const { notes, isLoading, canLoadMore, onLoadMore } = usePublicNoteList({ did })
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useATProtoLogin } from "@/hooks/useATProtoLogin.hook"
|
|||||||
import { useFollows } from "@/hooks/useFollows.hook"
|
import { useFollows } from "@/hooks/useFollows.hook"
|
||||||
import { useFollowingNoteList } from "@/hooks/useFollowingNoteList.hook"
|
import { useFollowingNoteList } from "@/hooks/useFollowingNoteList.hook"
|
||||||
import { usePublicNoteList } from "@/hooks/usePublicNoteList.hook"
|
import { usePublicNoteList } from "@/hooks/usePublicNoteList.hook"
|
||||||
|
import { toShortDid } from "@/modules/atproto/shortDid"
|
||||||
import { computed } from "vue"
|
import { computed } from "vue"
|
||||||
import { useRoute, useRouter } from "vue-router"
|
import { useRoute, useRouter } from "vue-router"
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ const following = useFollowingNoteList(follows, followingEnabled)
|
|||||||
<template #meta="{ note }">
|
<template #meta="{ note }">
|
||||||
<router-link
|
<router-link
|
||||||
v-if="all.getAuthor(note.did)"
|
v-if="all.getAuthor(note.did)"
|
||||||
:to="{ name: 'PublicNoteListByDidView', params: { did: note.did } }"
|
:to="{ name: 'PublicNoteListByDidView', params: { shortDid: toShortDid(note.did) } }"
|
||||||
class="link link-hover"
|
class="link link-hover"
|
||||||
>
|
>
|
||||||
{{ all.getAuthor(note.did) }}
|
{{ all.getAuthor(note.did) }}
|
||||||
@@ -84,7 +85,7 @@ const following = useFollowingNoteList(follows, followingEnabled)
|
|||||||
<template #meta="{ note }">
|
<template #meta="{ note }">
|
||||||
<router-link
|
<router-link
|
||||||
v-if="following.getAuthor(note.did)"
|
v-if="following.getAuthor(note.did)"
|
||||||
:to="{ name: 'PublicNoteListByDidView', params: { did: note.did } }"
|
:to="{ name: 'PublicNoteListByDidView', params: { shortDid: toShortDid(note.did) } }"
|
||||||
class="link link-hover"
|
class="link link-hover"
|
||||||
>
|
>
|
||||||
{{ following.getAuthor(note.did) }}
|
{{ following.getAuthor(note.did) }}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { getAuthor } from "@/modules/atproto/getAuthor"
|
|||||||
import type { PublicNoteRecord } from "@/modules/atproto/publicNote.types"
|
import type { PublicNoteRecord } from "@/modules/atproto/publicNote.types"
|
||||||
import { withATProtoImages } from "@/modules/atproto/withATProtoImages"
|
import { withATProtoImages } from "@/modules/atproto/withATProtoImages"
|
||||||
import { getUrl } from "@/modules/atproto/getUrl"
|
import { getUrl } from "@/modules/atproto/getUrl"
|
||||||
|
import { fromShortDid } from "@/modules/atproto/shortDid"
|
||||||
import { downloadFont } from "@/utils/downloadFont"
|
import { downloadFont } from "@/utils/downloadFont"
|
||||||
import { slugify } from "@/utils/slugify"
|
import { slugify } from "@/utils/slugify"
|
||||||
import { computedAsync } from "@vueuse/core"
|
import { computedAsync } from "@vueuse/core"
|
||||||
@@ -19,9 +20,9 @@ import ThemeSwap from "@/components/ThemeSwap.vue"
|
|||||||
import { useTitle } from "@vueuse/core"
|
import { useTitle } from "@vueuse/core"
|
||||||
import { displayLanguage } from "@/utils/displayLanguage"
|
import { displayLanguage } from "@/utils/displayLanguage"
|
||||||
|
|
||||||
const props = defineProps<{ did: string; rkey: string; slug?: string }>()
|
const props = defineProps<{ shortDid: string; rkey: string; slug?: string }>()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const did = computed(() => props.did)
|
const did = computed(() => fromShortDid(props.shortDid))
|
||||||
const rkey = computed(() => props.rkey)
|
const rkey = computed(() => props.rkey)
|
||||||
|
|
||||||
const author = computedAsync(async () => getAuthor(did.value))
|
const author = computedAsync(async () => getAuthor(did.value))
|
||||||
@@ -125,7 +126,7 @@ watch(
|
|||||||
<div class="note article">
|
<div class="note article">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<back-button
|
<back-button
|
||||||
:fallback="{ name: 'PublicNoteListByDidView', params: { did } }"
|
:fallback="{ name: 'PublicNoteListByDidView', params: { shortDid } }"
|
||||||
:prefer-fallback="false"
|
:prefer-fallback="false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -141,7 +142,7 @@ watch(
|
|||||||
<span> • </span>
|
<span> • </span>
|
||||||
</template>
|
</template>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ name: 'PublicNoteListByDidView', params: { did: did } }"
|
:to="{ name: 'PublicNoteListByDidView', params: { shortDid } }"
|
||||||
class="link link-hover"
|
class="link link-hover"
|
||||||
>
|
>
|
||||||
{{ author.handle }}
|
{{ author.handle }}
|
||||||
|
|||||||
Reference in New Issue
Block a user