kopia lustrzana https://github.com/elk-zone/elk
Merge branch 'main' into shuuji3/feat/emoji-reactions
commit
e174f23b66
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
const { as = 'div', active } = defineProps<{
|
||||
as: any
|
||||
as?: string
|
||||
active: boolean
|
||||
}>()
|
||||
|
||||
|
|
|
@ -35,15 +35,16 @@ const containerClass = computed(() => {
|
|||
'backdrop-blur': !getPreferences(userSettings, 'optimizeForLowPerformanceDevice'),
|
||||
}"
|
||||
>
|
||||
<div flex justify-between px5 py2 :class="{ 'xl:hidden': $route.name !== 'tag' }" class="native:xl:flex" border="b base">
|
||||
<div flex gap-3 items-center :overflow-hidden="!noOverflowHidden ? '' : false" py2 w-full>
|
||||
<NuxtLink
|
||||
v-if="backOnSmallScreen || back" flex="~ gap1" items-center btn-text p-0 xl:hidden
|
||||
<div flex justify-between gap-2 min-h-53px px5 py1 :class="{ 'xl:hidden': $route.name !== 'tag' }" class="native:xl:flex" border="b base">
|
||||
<div flex gap-2 items-center :overflow-hidden="!noOverflowHidden ? '' : false" w-full>
|
||||
<button
|
||||
v-if="backOnSmallScreen || back"
|
||||
btn-text flex items-center ms="-3" p-3 xl:hidden
|
||||
:aria-label="$t('nav.back')"
|
||||
@click="$router.go(-1)"
|
||||
>
|
||||
<div i-ri:arrow-left-line class="rtl-flip" />
|
||||
</NuxtLink>
|
||||
<div text-lg i-ri:arrow-left-line class="rtl-flip" />
|
||||
</button>
|
||||
<div :truncate="!noOverflowHidden ? '' : false" flex w-full data-tauri-drag-region class="native-mac:justify-start native-mac:text-center">
|
||||
<slot name="title" />
|
||||
</div>
|
||||
|
|
|
@ -33,17 +33,16 @@ router.afterEach(() => {
|
|||
{{ $t('app_name') }} <sup text-sm italic mt-1>{{ env === 'release' ? 'alpha' : env }}</sup>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
<div
|
||||
hidden xl:flex items-center me-8 mt-2 gap-1
|
||||
>
|
||||
<CommonTooltip :content="$t('nav.back')">
|
||||
<NuxtLink
|
||||
<div hidden xl:flex items-center me-6 mt-2 gap-1>
|
||||
<CommonTooltip :content="$t('nav.back')" :distance="0">
|
||||
<button
|
||||
type="button"
|
||||
:aria-label="$t('nav.back')"
|
||||
:class="{ 'pointer-events-none op0': !back || back === '/', 'xl:flex': $route.name !== 'tag' }"
|
||||
btn-text p-3 :class="{ 'pointer-events-none op0': !back || back === '/', 'xl:flex': $route.name !== 'tag' }"
|
||||
@click="$router.go(-1)"
|
||||
>
|
||||
<div text-xl i-ri:arrow-left-line class="rtl-flip" btn-text />
|
||||
</NuxtLink>
|
||||
<div text-xl i-ri:arrow-left-line class="rtl-flip" />
|
||||
</button>
|
||||
</CommonTooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -29,7 +29,7 @@ const emit = defineEmits<{
|
|||
|
||||
const { t } = useI18n()
|
||||
|
||||
const { threadItems, threadIsActive, publishThread } = threadComposer ?? useThreadComposer(draftKey)
|
||||
const { threadItems, threadIsActive, publishThread, threadIsSending } = threadComposer ?? useThreadComposer(draftKey)
|
||||
|
||||
const draft = computed({
|
||||
get: () => threadItems.value[draftItemIndex],
|
||||
|
@ -236,6 +236,59 @@ function stopQuestionMarkPropagation(e: KeyboardEvent) {
|
|||
if (e.key === '?')
|
||||
e.stopImmediatePropagation()
|
||||
}
|
||||
|
||||
const userSettings = useUserSettings()
|
||||
|
||||
const optimizeForLowPerformanceDevice = computed(() => getPreferences(userSettings.value, 'optimizeForLowPerformanceDevice'))
|
||||
|
||||
const languageDetectorInGlobalThis = 'LanguageDetector' in globalThis
|
||||
let supportsLanguageDetector = !optimizeForLowPerformanceDevice.value && languageDetectorInGlobalThis && await (globalThis as any).LanguageDetector.availability() === 'available'
|
||||
let languageDetector: { detect: (arg0: string, option: { signal: AbortSignal }) => any }
|
||||
// If the API is supported, but the model not loaded yet…
|
||||
if (languageDetectorInGlobalThis && !supportsLanguageDetector) {
|
||||
// …trigger the model download
|
||||
(globalThis as any).LanguageDetector.create().then((_languageDetector: { detect: (arg0: string) => any }) => {
|
||||
supportsLanguageDetector = true
|
||||
languageDetector = _languageDetector
|
||||
})
|
||||
}
|
||||
|
||||
function countLetters(text: string) {
|
||||
const segmenter = new Intl.Segmenter('und', { granularity: 'grapheme' })
|
||||
const letters = [...segmenter.segment(text)]
|
||||
return letters.length
|
||||
}
|
||||
|
||||
let detectLanguageAbortController = new AbortController()
|
||||
|
||||
const detectLanguage = useDebounceFn(async () => {
|
||||
if (!supportsLanguageDetector) {
|
||||
return
|
||||
}
|
||||
if (!languageDetector) {
|
||||
// maybe we dont want to mess with this with abort....
|
||||
languageDetector = await (globalThis as any).LanguageDetector.create()
|
||||
}
|
||||
// we stop previously running language detection process
|
||||
detectLanguageAbortController.abort()
|
||||
detectLanguageAbortController = new AbortController()
|
||||
const text = htmlToText(editor.value?.getHTML() || '')
|
||||
if (!text || countLetters(text) <= 5) {
|
||||
draft.value.params.language = preferredLanguage.value
|
||||
return
|
||||
}
|
||||
try {
|
||||
const detectedLanguage = (await languageDetector.detect(text, { signal: detectLanguageAbortController.signal }))[0].detectedLanguage
|
||||
draft.value.params.language = detectedLanguage === 'und' ? preferredLanguage.value : detectedLanguage.substring(0, 2)
|
||||
}
|
||||
catch (e) {
|
||||
// if error or abort we end up there
|
||||
if ((e as Error).name !== 'AbortError') {
|
||||
console.error(e)
|
||||
}
|
||||
draft.value.params.language = preferredLanguage.value
|
||||
}
|
||||
}, 500)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -310,6 +363,7 @@ function stopQuestionMarkPropagation(e: KeyboardEvent) {
|
|||
}"
|
||||
@keydown="stopQuestionMarkPropagation"
|
||||
@keydown.esc.prevent="editor?.commands.blur()"
|
||||
@keyup="detectLanguage"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -523,18 +577,18 @@ function stopQuestionMarkPropagation(e: KeyboardEvent) {
|
|||
<button
|
||||
v-if="!threadIsActive || isFinalItemOfThread"
|
||||
btn-solid rounded-3 text-sm w-full flex="~ gap1" items-center md:w-fit class="publish-button"
|
||||
:aria-disabled="isPublishDisabled || isExceedingCharacterLimit" aria-describedby="publish-tooltip"
|
||||
:disabled="isPublishDisabled || isExceedingCharacterLimit"
|
||||
:aria-disabled="isPublishDisabled || isExceedingCharacterLimit || threadIsSending" aria-describedby="publish-tooltip"
|
||||
:disabled="isPublishDisabled || isExceedingCharacterLimit || threadIsSending"
|
||||
@click="publish"
|
||||
>
|
||||
<span v-if="isSending" block animate-spin preserve-3d>
|
||||
<span v-if="isSending || threadIsSending" block animate-spin preserve-3d>
|
||||
<div block i-ri:loader-2-fill />
|
||||
</span>
|
||||
<span v-if="failedMessages.length" block>
|
||||
<div block i-carbon:face-dizzy-filled />
|
||||
</span>
|
||||
<template v-if="threadIsActive">
|
||||
<span>{{ $t('action.publish_thread') }} </span>
|
||||
<span>{{ !threadIsSending ? $t('action.publish_thread') : $t('state.publishing') }} </span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span v-if="draft.editingStatus">{{ $t('action.save_changes') }}</span>
|
||||
|
|
|
@ -11,7 +11,7 @@ const {
|
|||
withAction?: boolean
|
||||
}>()
|
||||
|
||||
const { translation } = useTranslation(status, getLanguageCode())
|
||||
const { translation } = await useTranslation(status, getLanguageCode())
|
||||
|
||||
const emojisObject = useEmojisFallback(() => status.emojis)
|
||||
const vnode = computed(() => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import type { mastodon } from 'masto'
|
||||
|
||||
const { actions = true, older, newer, hasOlder, hasNewer, main, ...props } = defineProps<{
|
||||
const { actions = true, older, newer, hasOlder, hasNewer, main, account, ...props } = defineProps<{
|
||||
status: mastodon.v1.Status
|
||||
followedTag?: string | null
|
||||
actions?: boolean
|
||||
|
@ -20,6 +20,7 @@ const { actions = true, older, newer, hasOlder, hasNewer, main, ...props } = def
|
|||
// When looking into a detailed view of a post, we can simplify the replying badges
|
||||
// to the main expanded post
|
||||
main?: mastodon.v1.Status
|
||||
account?: mastodon.v1.Account
|
||||
}>()
|
||||
|
||||
const userSettings = useUserSettings()
|
||||
|
@ -60,7 +61,10 @@ const timeago = useTimeAgo(() => status.value.createdAt, timeAgoOptions)
|
|||
const isSelfReply = computed(() => status.value.inReplyToAccountId === status.value.account.id)
|
||||
const collapseRebloggedBy = computed(() => rebloggedBy.value?.id === status.value.account.id)
|
||||
const isDM = computed(() => status.value.visibility === 'direct')
|
||||
const isPinned = computed(() => status.value.pinned)
|
||||
const isPinned = computed(
|
||||
() =>
|
||||
!!props.status.pinned && account?.id === status.value.account.id,
|
||||
)
|
||||
|
||||
const showUpperBorder = computed(() => newer && !directReply.value)
|
||||
const showReplyTo = computed(() => !replyToMain.value && !directReply.value)
|
||||
|
|
|
@ -9,7 +9,7 @@ const {
|
|||
toggle: _toggleTranslation,
|
||||
translation,
|
||||
enabled: isTranslationEnabled,
|
||||
} = useTranslation(status, getLanguageCode())
|
||||
} = await useTranslation(status, getLanguageCode())
|
||||
const preferenceHideTranslation = usePreferences('hideTranslation')
|
||||
|
||||
const showButton = computed(() =>
|
||||
|
|
|
@ -39,11 +39,11 @@ function getFollowedTag(status: mastodon.v1.Status): string | null {
|
|||
<template #default="{ item, older, newer, active }">
|
||||
<template v-if="virtualScroller">
|
||||
<DynamicScrollerItem :item="item" :active="active" tag="article">
|
||||
<StatusCard :followed-tag="getFollowedTag(item)" :status="item" :context="context" :older="older" :newer="newer" />
|
||||
<StatusCard :followed-tag="getFollowedTag(item)" :status="item" :context="context" :older="older" :newer="newer" :account="account" />
|
||||
</DynamicScrollerItem>
|
||||
</template>
|
||||
<template v-else>
|
||||
<StatusCard :followed-tag="getFollowedTag(item)" :status="item" :context="context" :older="older" :newer="newer" />
|
||||
<StatusCard :followed-tag="getFollowedTag(item)" :status="item" :context="context" :older="older" :newer="newer" :account="account" />
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="context === 'account' " #done="{ items }">
|
||||
|
|
|
@ -104,11 +104,12 @@ export function parseMastodonHTML(
|
|||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/`/g, '`')
|
||||
.replace(/\*/g, '*')
|
||||
const classes = lang ? ` class="language-${lang}"` : ''
|
||||
return `><pre><code${classes}>${code}</code></pre>`
|
||||
})
|
||||
.replace(/`([^`\n]*)`/g, (_1, raw) => {
|
||||
return raw ? `<code>${htmlToText(raw).replace(/</g, '<').replace(/>/g, '>')}</code>` : ''
|
||||
return raw ? `<code>${htmlToText(raw).replace(/</g, '<').replace(/>/g, '>').replace(/\*/g, '*')}</code>` : ''
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ export const statusVisibilities = [
|
|||
},
|
||||
{
|
||||
value: 'unlisted',
|
||||
icon: 'i-ri:lock-unlock-line',
|
||||
icon: 'i-ri:moon-line',
|
||||
},
|
||||
{
|
||||
value: 'private',
|
||||
|
|
|
@ -95,9 +95,9 @@ export async function toggleMuteAccount(relationship: mastodon.v1.Relationship,
|
|||
relationship!.muting = !relationship!.muting
|
||||
relationship = relationship!.muting
|
||||
? await client.value.v1.accounts.$select(account.id).mute({
|
||||
duration,
|
||||
notifications,
|
||||
})
|
||||
duration,
|
||||
notifications,
|
||||
})
|
||||
: await client.value.v1.accounts.$select(account.id).unmute()
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,10 @@ export const supportedTranslationCodes = [
|
|||
'zh',
|
||||
] as const
|
||||
|
||||
const translationAPISupported = 'Translator' in globalThis && 'LanguageDetector' in globalThis
|
||||
|
||||
const anchorMarkupRegEx = /<a[^>]*>.*?<\/a>/g
|
||||
|
||||
export function getLanguageCode() {
|
||||
let code = 'en'
|
||||
const getCode = (code: string) => code.replace(/-.*$/, '')
|
||||
|
@ -58,6 +62,13 @@ interface TranslationErr {
|
|||
}
|
||||
}
|
||||
|
||||
function replaceTranslatedLinksWithOriginal(text: string) {
|
||||
return text.replace(anchorMarkupRegEx, (match) => {
|
||||
const tagLink = anchorMarkupRegEx.exec(text)
|
||||
return tagLink ? tagLink[0] : match
|
||||
})
|
||||
}
|
||||
|
||||
export async function translateText(text: string, from: string | null | undefined, to: string) {
|
||||
const config = useRuntimeConfig()
|
||||
const status = ref({
|
||||
|
@ -65,7 +76,6 @@ export async function translateText(text: string, from: string | null | undefine
|
|||
error: '',
|
||||
text: '',
|
||||
})
|
||||
const regex = /<a[^>]*>.*?<\/a>/g
|
||||
try {
|
||||
const response = await ($fetch as any)(config.public.translateApi, {
|
||||
method: 'POST',
|
||||
|
@ -78,11 +88,7 @@ export async function translateText(text: string, from: string | null | undefine
|
|||
},
|
||||
}) as TranslationResponse
|
||||
status.value.success = true
|
||||
// replace the translated links with the original
|
||||
status.value.text = response.translatedText.replace(regex, (match) => {
|
||||
const tagLink = regex.exec(text)
|
||||
return tagLink ? tagLink[0] : match
|
||||
})
|
||||
status.value.text = replaceTranslatedLinksWithOriginal(response.translatedText)
|
||||
}
|
||||
catch (err) {
|
||||
// TODO: improve type
|
||||
|
@ -102,17 +108,27 @@ const translations = new WeakMap<mastodon.v1.Status | mastodon.v1.StatusEdit, {
|
|||
error: string
|
||||
}>()
|
||||
|
||||
export function useTranslation(status: mastodon.v1.Status | mastodon.v1.StatusEdit, to: string) {
|
||||
export async function useTranslation(status: mastodon.v1.Status | mastodon.v1.StatusEdit, to: string) {
|
||||
if (!translations.has(status))
|
||||
translations.set(status, reactive({ visible: false, text: '', success: false, error: '' }))
|
||||
|
||||
const translation = translations.get(status)!
|
||||
const userSettings = useUserSettings()
|
||||
|
||||
const shouldTranslate = 'language' in status && status.language && status.language !== to
|
||||
&& supportedTranslationCodes.includes(to as any)
|
||||
&& supportedTranslationCodes.includes(status.language as any)
|
||||
&& !userSettings.value.disabledTranslationLanguages.includes(status.language)
|
||||
let shouldTranslate = false
|
||||
if ('language' in status) {
|
||||
shouldTranslate = typeof status.language === 'string' && status.language !== to && !userSettings.value.disabledTranslationLanguages.includes(status.language)
|
||||
if (!translationAPISupported) {
|
||||
shouldTranslate = shouldTranslate && supportedTranslationCodes.includes(to as any)
|
||||
&& supportedTranslationCodes.includes(status.language as any)
|
||||
}
|
||||
else {
|
||||
shouldTranslate = shouldTranslate && (await (globalThis as any).Translator.availability({
|
||||
sourceLanguage: status.language,
|
||||
targetLanguage: to,
|
||||
})) !== 'unavailable'
|
||||
}
|
||||
}
|
||||
const enabled = /*! !useRuntimeConfig().public.translateApi && */ shouldTranslate
|
||||
|
||||
async function toggle() {
|
||||
|
@ -120,12 +136,57 @@ export function useTranslation(status: mastodon.v1.Status | mastodon.v1.StatusEd
|
|||
return
|
||||
|
||||
if (!translation.text) {
|
||||
const translated = await translateText(status.content, status.language, to)
|
||||
let translated = {
|
||||
value: {
|
||||
error: '',
|
||||
text: '',
|
||||
success: false,
|
||||
},
|
||||
}
|
||||
if (translationAPISupported && 'language' in status) {
|
||||
let sourceLanguage = status.language
|
||||
if (!sourceLanguage) {
|
||||
const languageDetector = await (globalThis as any).LanguageDetector.create()
|
||||
// Make sure HTML markup doesn't derail language detection.
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = status.content
|
||||
// eslint-disable-next-line unicorn/prefer-dom-node-text-content
|
||||
const detectedLanguages = await languageDetector.detect(div.innerText)
|
||||
sourceLanguage = detectedLanguages[0].detectedLanguage
|
||||
if (sourceLanguage === 'und') {
|
||||
throw new Error('Could not detect source language.')
|
||||
}
|
||||
}
|
||||
const translator = await (globalThis as any).Translator.create({
|
||||
sourceLanguage,
|
||||
targetLanguage: to,
|
||||
})
|
||||
try {
|
||||
let text = await translator.translate(status.content)
|
||||
text = replaceTranslatedLinksWithOriginal(text)
|
||||
translated.value = {
|
||||
error: '',
|
||||
text,
|
||||
success: true,
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
translated.value = {
|
||||
error: (error as Error).message,
|
||||
text: '',
|
||||
success: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ('language' in status) {
|
||||
translated = await translateText(status.content, status.language, to)
|
||||
}
|
||||
}
|
||||
translation.error = translated.value.error
|
||||
translation.text = translated.value.text
|
||||
translation.success = translated.value.success
|
||||
}
|
||||
|
||||
translation.visible = !translation.visible
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ export function useThreadComposer(draftKey: string, initial?: () => DraftItem) {
|
|||
*/
|
||||
const threadIsActive = computed<boolean>(() => draftItems.value.length > 1)
|
||||
|
||||
const threadIsSending = ref(false)
|
||||
|
||||
/**
|
||||
* Add an item to the thread
|
||||
*/
|
||||
|
@ -44,6 +46,7 @@ export function useThreadComposer(draftKey: string, initial?: () => DraftItem) {
|
|||
async function publishThread() {
|
||||
const allFailedMessages: Array<string> = []
|
||||
const isAReplyThread = Boolean(draftItems.value[0].params.inReplyToId)
|
||||
threadIsSending.value = true
|
||||
|
||||
let lastPublishedStatus: mastodon.v1.Status | null = null
|
||||
let amountPublished = 0
|
||||
|
@ -72,6 +75,7 @@ export function useThreadComposer(draftKey: string, initial?: () => DraftItem) {
|
|||
}
|
||||
// Remove all published items from the thread
|
||||
draftItems.value.splice(0, amountPublished)
|
||||
threadIsSending.value = false
|
||||
|
||||
// If we have errors, return them
|
||||
if (allFailedMessages.length > 0)
|
||||
|
@ -90,5 +94,6 @@ export function useThreadComposer(draftKey: string, initial?: () => DraftItem) {
|
|||
addThreadItem,
|
||||
removeThreadItem,
|
||||
publishThread,
|
||||
threadIsSending,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@ catch (err) {
|
|||
|
||||
<template>
|
||||
<MainContent text-base grid gap-3 m3>
|
||||
<img rounded-3 :src="instance.thumbnail.url">
|
||||
<img v-if="instance !== undefined" rounded-3 :src="instance.thumbnail.url">
|
||||
</MainContent>
|
||||
</template>
|
||||
|
|
|
@ -13,6 +13,6 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@nuxt-themes/docus": "^1.15.1",
|
||||
"nuxt": "^3.17.3"
|
||||
"nuxt": "^3.18.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,7 +165,8 @@
|
|||
},
|
||||
"preferences": {
|
||||
"grayscale_mode": "Tema en escala de grises",
|
||||
"hide_username_emojis_description": "Oculta, de la historia, los emojis en los nombres de usuario. Los emojis seguirán visibles en los perfiles."
|
||||
"hide_username_emojis_description": "Oculta, de la historia, los emojis en los nombres de usuario. Los emojis seguirán visibles en los perfiles.",
|
||||
"unmute_videos": "Sonido de video activado por defecto"
|
||||
},
|
||||
"profile": {
|
||||
"appearance": {
|
||||
|
|
|
@ -226,7 +226,9 @@
|
|||
"manage": "Administrar listas",
|
||||
"modify_account": "Modificar listas con cuenta",
|
||||
"remove_account": "Eliminar cuenta de la lista",
|
||||
"save": "Guardar"
|
||||
"save": "Guardar",
|
||||
"search_following_desc": "Buscar personas a las que sigues",
|
||||
"search_following_placeholder": "Buscar entre las personas a las que sigues"
|
||||
},
|
||||
"magic_keys": {
|
||||
"dialog_header": "Atajos de teclado",
|
||||
|
@ -334,10 +336,12 @@
|
|||
"zen_mode": "Modo Zen"
|
||||
},
|
||||
"notification": {
|
||||
"and": "y",
|
||||
"favourited_post": "marcó como favorita tu publicación",
|
||||
"followed_you": "te ha seguido",
|
||||
"followed_you_count": "{0} personas te siguieron|{0} persona te siguió|{0} personas te siguieron",
|
||||
"missing_type": "MISSING notification.type:",
|
||||
"others": "{0} personas|{0} persona|{0} personas",
|
||||
"reblogged_post": "retooteó tu publicación",
|
||||
"reported": "{0} reportó {1}",
|
||||
"request_to_follow": "ha solicitado seguirte",
|
||||
|
@ -559,6 +563,7 @@
|
|||
"label": "Preferencias",
|
||||
"optimize_for_low_performance_device": "Optimizar para dispositivos de bajo rendimiento",
|
||||
"title": "Funcionalidades experimentales",
|
||||
"unmute_videos": "Sonido de vídeo activado por defecto",
|
||||
"use_star_favorite_icon": "Utilizar icono de estrella para favoritos",
|
||||
"user_picker": "Selector de usuarios",
|
||||
"user_picker_description": "Muestra todos los avatares de las cuentas registradas en la parte inferior izquierda para que puedas cambiar rápidamente entre ellos.",
|
||||
|
@ -637,7 +642,8 @@
|
|||
"poll": {
|
||||
"count": "{0} votos|{0} voto|{0} votos",
|
||||
"ends": "finaliza {0}",
|
||||
"finished": "finalizada {0}"
|
||||
"finished": "finalizada {0}",
|
||||
"update": "Actualizar encuesta"
|
||||
},
|
||||
"replying_to": "Respondiendo a {0}",
|
||||
"show_full_thread": "Mostrar hilo completo",
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import type { Ref } from 'vue'
|
||||
import type { UnwrapNestedRefs } from 'vue'
|
||||
import type { Ref, UnwrapNestedRefs } from 'vue'
|
||||
|
||||
export interface PwaInjection {
|
||||
isInstalled: boolean
|
||||
|
|
28
package.json
28
package.json
|
@ -68,7 +68,7 @@
|
|||
"@vueuse/motion": "2.2.6",
|
||||
"@vueuse/nuxt": "^13.2.0",
|
||||
"blurhash": "^2.0.5",
|
||||
"browser-fs-access": "^0.35.0",
|
||||
"browser-fs-access": "^0.38.0",
|
||||
"cheerio": "^1.0.0",
|
||||
"chroma-js": "^3.0.0",
|
||||
"emoji-mart": "^5.5.2",
|
||||
|
@ -117,7 +117,7 @@
|
|||
"ws": "^8.15.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^4.13.1",
|
||||
"@antfu/eslint-config": "^5.1.0",
|
||||
"@antfu/ni": "^24.4.0",
|
||||
"@types/chroma-js": "^3.1.1",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
|
@ -127,23 +127,23 @@
|
|||
"@types/wicg-file-system-access": "^2023.10.6",
|
||||
"@types/ws": "^8.18.1",
|
||||
"@unlazy/nuxt": "^0.12.4",
|
||||
"@unocss/eslint-config": "^66.1.2",
|
||||
"@unocss/eslint-config": "^66.4.1",
|
||||
"@vue/test-utils": "2.4.6",
|
||||
"bumpp": "^10.1.1",
|
||||
"bumpp": "^10.2.2",
|
||||
"consola": "^3.4.2",
|
||||
"eslint": "^9.27.0",
|
||||
"eslint": "^9.32.0",
|
||||
"eslint-plugin-format": "^1.0.1",
|
||||
"flat": "^6.0.1",
|
||||
"fs-extra": "^11.3.0",
|
||||
"lint-staged": "^15.5.2",
|
||||
"nuxt": "^3.17.3",
|
||||
"prettier": "^3.5.3",
|
||||
"sharp": "^0.34.1",
|
||||
"nuxt": "^3.18.1",
|
||||
"prettier": "^3.6.2",
|
||||
"sharp": "^0.34.3",
|
||||
"sharp-ico": "^0.1.5",
|
||||
"simple-git-hooks": "^2.13.0",
|
||||
"tsx": "^4.19.4",
|
||||
"simple-git-hooks": "^2.13.1",
|
||||
"tsx": "^4.20.3",
|
||||
"typescript": "^5.4.4",
|
||||
"vitest": "3.1.3",
|
||||
"vitest": "3.2.4",
|
||||
"vue-tsc": "^2.1.6"
|
||||
},
|
||||
"pnpm": {
|
||||
|
@ -152,9 +152,9 @@
|
|||
}
|
||||
},
|
||||
"resolutions": {
|
||||
"nuxt-component-meta": "0.11.0",
|
||||
"unstorage": "^1.16.0",
|
||||
"vitest": "3.1.3",
|
||||
"nuxt-component-meta": "0.13.0",
|
||||
"unstorage": "^1.16.1",
|
||||
"vitest": "3.2.4",
|
||||
"vue": "^3.5.4"
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
declare module 'page-lifecycle/dist/lifecycle.mjs' {
|
||||
type PageLifecycleState = 'active' | 'passive' | 'hidden' | 'frozen' | 'terminated'
|
||||
type PageLifecycleState = 'active' | 'passive' | 'hidden' | 'frozen' | 'terminated'
|
||||
|
||||
interface PageLifecycleEvent extends Event {
|
||||
newState: PageLifecycleState
|
||||
oldState: PageLifecycleState
|
||||
}
|
||||
interface PageLifecycle extends EventTarget {
|
||||
get state(): PageLifecycleState
|
||||
get pageWasDiscarded(): boolean
|
||||
addUnsavedChanges: (id: symbol | any) => void
|
||||
removeUnsavedChanges: (id: symbol | any) => void
|
||||
addEventListener: (type: string, listener: (evt: PageLifecycleEvent) => void) => void
|
||||
}
|
||||
const lifecycle: PageLifecycle
|
||||
export default lifecycle
|
||||
interface PageLifecycleEvent extends Event {
|
||||
newState: PageLifecycleState
|
||||
oldState: PageLifecycleState
|
||||
}
|
||||
interface PageLifecycle extends EventTarget {
|
||||
get state(): PageLifecycleState
|
||||
get pageWasDiscarded(): boolean
|
||||
addUnsavedChanges: (id: symbol | any) => void
|
||||
removeUnsavedChanges: (id: symbol | any) => void
|
||||
addEventListener: (type: string, listener: (evt: PageLifecycleEvent) => void) => void
|
||||
}
|
||||
const lifecycle: PageLifecycle
|
||||
export default lifecycle
|
||||
}
|
||||
|
|
6709
pnpm-lock.yaml
6709
pnpm-lock.yaml
Plik diff jest za duży
Load Diff
|
@ -60,7 +60,7 @@ async function fetchAppInfo(origin: string, server: string) {
|
|||
},
|
||||
body: {
|
||||
client_name: APP_NAME + (env !== 'release' ? ` (${env})` : ''),
|
||||
website: 'https://elk.zone',
|
||||
website: origin,
|
||||
redirect_uris: getRedirectURI(origin, server),
|
||||
scopes: 'read write follow push',
|
||||
},
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`content-rich > asterisk paris in code block 1`] = `"<p><pre class="code-block">1 * 2 * 3</pre></p>"`;
|
||||
|
||||
exports[`content-rich > asterisk paris in inline code 1`] = `
|
||||
"<p><code>1 * 2 * 3</code></p>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`content-rich > block with backticks 1`] = `"<p><pre class="code-block">[(\`number string) (\`tag string)]</pre></p>"`;
|
||||
|
||||
exports[`content-rich > block with injected html, with a known language 1`] = `
|
||||
|
|
|
@ -186,6 +186,16 @@ describe('content-rich', () => {
|
|||
`)
|
||||
expect(formatted).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it ('asterisk paris in inline code', async () => {
|
||||
const { formatted } = await render('<p>`1 * 2 * 3`</p>')
|
||||
expect(formatted).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it ('asterisk paris in code block', async () => {
|
||||
const { formatted } = await render('<p>```<br />1 * 2 * 3<br />```</p>')
|
||||
expect(formatted).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('editor', () => {
|
||||
|
|
Ładowanie…
Reference in New Issue