Merge branch 'main' of github.com:elk-zone/elk into feat/promote-media-player-as-not-experimental
This commit is contained in:
commit
1e8b5814ac
409 changed files with 11724 additions and 9763 deletions
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
|
|
@ -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
22
.github/workflows/provenance.yml
vendored
Normal 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
|
||||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
2
.github/workflows/semantic-pull-request.yml
vendored
2
.github/workflows/semantic-pull-request.yml
vendored
|
|
@ -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
1
.gitignore
vendored
|
|
@ -4,6 +4,7 @@ dist
|
||||||
.output
|
.output
|
||||||
.pnpm-store
|
.pnpm-store
|
||||||
.nuxt
|
.nuxt
|
||||||
|
.data
|
||||||
.env
|
.env
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.idea/
|
.idea/
|
||||||
|
|
|
||||||
4
.npmrc
4
.npmrc
|
|
@ -1,4 +0,0 @@
|
||||||
shamefully-hoist=true
|
|
||||||
shell-emulator=true
|
|
||||||
ignore-workspace-root-check=true
|
|
||||||
package-manager-strict=false
|
|
||||||
2
.nvmrc
2
.nvmrc
|
|
@ -1 +1 @@
|
||||||
22
|
22
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
19
app/augments.d.ts
vendored
Normal 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>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -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[]
|
||||||
|
|
@ -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
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
|
@ -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"
|
||||||
>
|
>
|
||||||
23
app/components/list/AccountSearchResult.vue
Normal file
23
app/components/list/AccountSearchResult.vue
Normal 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>
|
||||||
|
|
@ -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 />
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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>()
|
||||||
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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({
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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
Loading…
Reference in a new issue