Merge branch 'main' of github.com:elk-zone/elk into feat/promote-media-player-as-not-experimental

This commit is contained in:
Ayo Ayco 2025-11-06 16:57:36 +01:00
commit 1e8b5814ac
409 changed files with 11724 additions and 9763 deletions

View file

@ -17,12 +17,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
# workaround for npm registry key change # workaround for npm registry key change
# ref. `pnpm@10.1.0` / `pnpm@9.15.4` cannot be installed due to key id mismatch · Issue #612 · nodejs/corepack # ref. `pnpm@10.1.0` / `pnpm@9.15.4` cannot be installed due to key id mismatch · Issue #612 · nodejs/corepack
# - https://github.com/nodejs/corepack/issues/612#issuecomment-2629496091 # - https://github.com/nodejs/corepack/issues/612#issuecomment-2629496091
- run: npm i -g corepack@latest && corepack enable - run: npm i -g corepack@latest && corepack enable
- uses: actions/setup-node@v4.4.0 - uses: actions/setup-node@v6.0.0
with: with:
node-version-file: .nvmrc node-version-file: .nvmrc

View file

@ -16,7 +16,7 @@ jobs:
packages: write packages: write
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Docker meta - name: Docker meta
id: metal id: metal
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5

22
.github/workflows/provenance.yml vendored Normal file
View file

@ -0,0 +1,22 @@
name: ci
on:
push:
branches:
- main
pull_request:
branches:
- main
permissions:
contents: read
jobs:
check-provenance:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Check provenance downgrades
uses: danielroe/provenance-action@41bcc969e579d9e29af08ba44fcbfdf95cee6e6c # v0.1.1
with:
fail-on-provenance-change: true

View file

@ -12,12 +12,12 @@ jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set node - name: Set node
uses: actions/setup-node@v4 uses: actions/setup-node@v6
with: with:
node-version-file: .nvmrc node-version-file: .nvmrc

View file

@ -19,6 +19,6 @@ jobs:
name: Semantic Pull Request name: Semantic Pull Request
steps: steps:
- name: Validate PR title - name: Validate PR title
uses: amannn/action-semantic-pull-request@v5.5.3 uses: amannn/action-semantic-pull-request@v6.1.1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.gitignore vendored
View file

@ -4,6 +4,7 @@ dist
.output .output
.pnpm-store .pnpm-store
.nuxt .nuxt
.data
.env .env
.DS_Store .DS_Store
.idea/ .idea/

4
.npmrc
View file

@ -1,4 +0,0 @@
shamefully-hoist=true
shell-emulator=true
ignore-workspace-root-check=true
package-manager-strict=false

2
.nvmrc
View file

@ -1 +1 @@
22 22

View file

@ -17,13 +17,12 @@ RUN apk add git --no-cache
# Prepare build deps ( ignore postinstall scripts for now ) # Prepare build deps ( ignore postinstall scripts for now )
COPY package.json ./ COPY package.json ./
COPY .npmrc ./
COPY pnpm-lock.yaml ./ COPY pnpm-lock.yaml ./
COPY patches ./patches
RUN pnpm i --frozen-lockfile --ignore-scripts RUN pnpm i --frozen-lockfile --ignore-scripts
# Copy all source files # Copy all source files
COPY . ./ COPY . ./
RUN pnpm nuxt prepare
# Run full install with every postinstall script ( This needs project file ) # Run full install with every postinstall script ( This needs project file )
RUN pnpm i --frozen-lockfile RUN pnpm i --frozen-lockfile

View file

@ -45,7 +45,7 @@ One could put Elk behind popular reverse proxies with SSL Handling like Traefik,
1. got into new source dir: ```cd elk``` 1. got into new source dir: ```cd elk```
1. create local storage directory for settings: ```mkdir elk-storage``` 1. create local storage directory for settings: ```mkdir elk-storage```
1. adjust permissions of storage dir: ```sudo chown 911:911 ./elk-storage``` 1. adjust permissions of storage dir: ```sudo chown 911:911 ./elk-storage```
1. start container: ```docker-compose up --build -d``` 1. start container: ```docker compose up --build -d```
> [!NOTE] > [!NOTE]
> The provided Dockerfile creates a container which will eventually run Elk as non-root user and create a persistent named Docker volume upon first start (if that volume does not yet exist). This volume is always created with root permission. Failing to change the permissions of ```/elk/data``` inside this volume to UID:GID 911 (as specified for Elk in the Dockerfile) will prevent Elk from storing it's config for user accounts. You either have to fix the permission in the created named volume, or mount a directory with the correct permission to ```/elk/data``` into the container. > The provided Dockerfile creates a container which will eventually run Elk as non-root user and create a persistent named Docker volume upon first start (if that volume does not yet exist). This volume is always created with root permission. Failing to change the permissions of ```/elk/data``` inside this volume to UID:GID 911 (as specified for Elk in the Dockerfile) will prevent Elk from storing it's config for user accounts. You either have to fix the permission in the created named volume, or mount a directory with the correct permission to ```/elk/data``` into the container.
@ -55,6 +55,7 @@ One could put Elk behind popular reverse proxies with SSL Handling like Traefik,
These are known deployments using Elk as an alternative Web client for Mastodon servers or as a base for other projects in the fediverse: These are known deployments using Elk as an alternative Web client for Mastodon servers or as a base for other projects in the fediverse:
- [elk.fedified.com](https://elk.fedified.com) - Use Elk to log into any compatible instance - [elk.fedified.com](https://elk.fedified.com) - Use Elk to log into any compatible instance
- [elk.mastodon.com.pl](https://elk.mastodon.com.pl) - Use Elk for the `mastodon.com.pl` Server
- [elk.me.uk](https://elk.me.uk) - Use Elk to log into any compatible instance, hosted on Google Cloud Run with no Cloudflare proxy - [elk.me.uk](https://elk.me.uk) - Use Elk to log into any compatible instance, hosted on Google Cloud Run with no Cloudflare proxy
- [elk.h4.io](https://elk.h4.io) - Use Elk for the `h4.io` Server - [elk.h4.io](https://elk.h4.io) - Use Elk for the `h4.io` Server
- [elk.universeodon.com](https://elk.universeodon.com) - Use Elk for the Universeodon Server - [elk.universeodon.com](https://elk.universeodon.com) - Use Elk for the Universeodon Server

19
app/augments.d.ts vendored Normal file
View file

@ -0,0 +1,19 @@
export {}
declare module '#app' {
interface PageMeta {
wideLayout?: boolean
}
interface RuntimeNuxtHooks {
'elk-logo:click': () => void
}
}
declare global {
namespace NodeJS {
interface Process {
mock?: Record<string, any>
}
}
}

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { mastodon } from 'masto' import type { mastodon } from 'masto'
import { toggleFollowAccount, useRelationship } from '~~/composables/masto/relationship' import { toggleFollowAccount, useRelationship } from '~/composables/masto/relationship'
const { account, context, command, ...props } = defineProps<{ const { account, context, command, ...props } = defineProps<{
account: mastodon.v1.Account account: mastodon.v1.Account

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { mastodon } from 'masto' import type { mastodon } from 'masto'
import { toggleBlockAccount, toggleBlockDomain, toggleMuteAccount } from '~~/composables/masto/relationship' import { toggleBlockAccount, toggleBlockDomain, toggleMuteAccount } from '~/composables/masto/relationship'
const { account } = defineProps<{ const { account } = defineProps<{
account: mastodon.v1.Account account: mastodon.v1.Account

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import type { CommonRouteTabOption } from '~/types' import type { CommonRouteTabOption } from '#shared/types'
const { t } = useI18n() const { t } = useI18n()
const route = useRoute() const route = useRoute()

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import type { CommonRouteTabMoreOption, CommonRouteTabOption } from '~/types' import type { CommonRouteTabMoreOption, CommonRouteTabOption } from '#shared/types'
const { options, command, preventScrollTop = false } = defineProps<{ const { options, command, preventScrollTop = false } = defineProps<{
options: CommonRouteTabOption[] options: CommonRouteTabOption[]

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
const { as = 'div', active } = defineProps<{ const { as = 'div', active } = defineProps<{
as: any as?: string
active: boolean active: boolean
}>() }>()

View file

@ -44,6 +44,7 @@ async function edit() {
<button <button
text-sm p2 border-1 transition-colors text-sm p2 border-1 transition-colors
border-dark border-dark
bg-base
btn-action-icon btn-action-icon
@click="edit" @click="edit"
> >

View file

@ -0,0 +1,23 @@
<script setup lang="ts">
import type { SearchResult } from '~/composables/masto/search'
defineProps<{
result: SearchResult
active: boolean
}>()
</script>
<template>
<CommonScrollIntoView
as="div"
:active="active"
py2 block px2
:aria-selected="active"
:class="{ 'bg-active': active }"
>
<AccountInfo
v-if="result.type === 'account'"
:account="result.data"
/>
</CommonScrollIntoView>
</template>

View file

@ -30,21 +30,21 @@ const containerClass = computed(() => {
sticky top-0 z-20 sticky top-0 z-20
pt="[env(safe-area-inset-top,0)]" pt="[env(safe-area-inset-top,0)]"
bg="[rgba(var(--rgb-bg-base),0.7)]" bg="[rgba(var(--rgb-bg-base),0.7)]"
class="native:lg:w-[calc(100vw-5rem)] native:xl:w-[calc(135%+(100vw-1200px)/2)]"
:class="{ :class="{
'backdrop-blur': !getPreferences(userSettings, 'optimizeForLowPerformanceDevice'), '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 justify-between gap-2 min-h-53px px5 py1 :class="{ 'xl:hidden': $route.name !== 'tag' }" border="b base">
<div flex gap-3 items-center :overflow-hidden="!noOverflowHidden ? '' : false" py2 w-full> <div flex gap-2 items-center :overflow-hidden="!noOverflowHidden ? '' : false" w-full>
<NuxtLink <button
v-if="backOnSmallScreen || back" flex="~ gap1" items-center btn-text p-0 xl:hidden v-if="backOnSmallScreen || back"
btn-text flex items-center ms="-3" p-3 xl:hidden
:aria-label="$t('nav.back')" :aria-label="$t('nav.back')"
@click="$router.go(-1)" @click="$router.go(-1)"
> >
<div i-ri:arrow-left-line class="rtl-flip" /> <div text-lg i-ri:arrow-left-line class="rtl-flip" />
</NuxtLink> </button>
<div :truncate="!noOverflowHidden ? '' : false" flex w-full data-tauri-drag-region class="native-mac:justify-start native-mac:text-center"> <div :truncate="!noOverflowHidden ? '' : false" flex w-full class="native-mac:justify-start native-mac:text-center">
<slot name="title" /> <slot name="title" />
</div> </div>
<div sm:hidden h-7 w-1px /> <div sm:hidden h-7 w-1px />

View file

@ -13,9 +13,9 @@ watchEffect(() => {
} }
const duration const duration
= days.value * 24 * 60 * 60 = days.value * 24 * 60 * 60
+ hours.value * 60 * 60 + hours.value * 60 * 60
+ minutes.value * 60 + minutes.value * 60
if (duration <= 0) { if (duration <= 0) {
isValid.value = false isValid.value = false

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ConfirmDialogChoice, ConfirmDialogOptions } from '~/types' import type { ConfirmDialogChoice, ConfirmDialogOptions } from '#shared/types'
const { extraOptionType } = defineProps<ConfirmDialogOptions>() const { extraOptionType } = defineProps<ConfirmDialogOptions>()

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ConfirmDialogChoice } from '#shared/types'
import type { mastodon } from 'masto' import type { mastodon } from 'masto'
import type { ConfirmDialogChoice } from '~/types'
import { import {
isCommandPanelOpen, isCommandPanelOpen,
isConfirmDialogOpen, isConfirmDialogOpen,
@ -82,7 +82,7 @@ function handleFavouritedBoostedByClose() {
> >
<ModalMediaPreview v-if="isMediaPreviewOpen" @close="closeMediaPreview()" /> <ModalMediaPreview v-if="isMediaPreviewOpen" @close="closeMediaPreview()" />
</ModalDialog> </ModalDialog>
<ModalDialog v-model="isEditHistoryDialogOpen" max-w-125> <ModalDialog v-model="isEditHistoryDialogOpen" :focus-first-element="false" max-w-125>
<StatusEditPreview v-if="statusEdit" :edit="statusEdit" /> <StatusEditPreview v-if="statusEdit" :edit="statusEdit" />
</ModalDialog> </ModalDialog>
<ModalDialog v-model="isCommandPanelOpen" max-w-fit flex> <ModalDialog v-model="isCommandPanelOpen" max-w-fit flex>

View file

@ -10,6 +10,7 @@ const {
closeByMask = true, closeByMask = true,
useVIf = true, useVIf = true,
keepAlive = false, keepAlive = false,
focusFirstElement = true,
} = defineProps<{ } = defineProps<{
// level of depth // level of depth
zIndex?: number zIndex?: number
@ -21,6 +22,8 @@ const {
keepAlive?: boolean keepAlive?: boolean
// The aria-labelledby id for the dialog. // The aria-labelledby id for the dialog.
dialogLabelledBy?: string dialogLabelledBy?: string
// Whether to focus on the first element when the modal opens.
focusFirstElement?: boolean
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
@ -45,6 +48,7 @@ const { activate } = useFocusTrap(elDialogRoot, {
escapeDeactivates: true, escapeDeactivates: true,
preventScroll: true, preventScroll: true,
returnFocusOnDeactivate: true, returnFocusOnDeactivate: true,
initialFocus: focusFirstElement ? undefined : false,
}) })
defineExpose({ defineExpose({

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import type { ErrorDialogData } from '~/types' import type { ErrorDialogData } from '#shared/types'
defineProps<ErrorDialogData>() defineProps<ErrorDialogData>()
</script> </script>

View file

@ -18,7 +18,7 @@ router.afterEach(() => {
</script> </script>
<template> <template>
<div flex justify-between sticky top-0 bg-base z-1 py-4 native:py-7 data-tauri-drag-region> <div flex justify-between sticky top-0 bg-base z-1 py-4>
<NuxtLink <NuxtLink
flex items-end gap-3 flex items-end gap-3
py2 px-5 py2 px-5
@ -33,17 +33,16 @@ router.afterEach(() => {
{{ $t('app_name') }} <sup text-sm italic mt-1>{{ env === 'release' ? 'alpha' : env }}</sup> {{ $t('app_name') }} <sup text-sm italic mt-1>{{ env === 'release' ? 'alpha' : env }}</sup>
</div> </div>
</NuxtLink> </NuxtLink>
<div <div hidden xl:flex items-center me-6 mt-2 gap-1>
hidden xl:flex items-center me-8 mt-2 gap-1 <CommonTooltip :content="$t('nav.back')" :distance="0">
> <button
<CommonTooltip :content="$t('nav.back')"> type="button"
<NuxtLink
:aria-label="$t('nav.back')" :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)" @click="$router.go(-1)"
> >
<div text-xl i-ri:arrow-left-line class="rtl-flip" btn-text /> <div text-xl i-ri:arrow-left-line class="rtl-flip" />
</NuxtLink> </button>
</CommonTooltip> </CommonTooltip>
</div> </div>
</div> </div>

Some files were not shown because too many files have changed in this diff Show more