mirror of
https://github.com/Afilmory/afilmory
synced 2026-02-01 14:44:48 +00:00
refactor: remove RSS support from social configuration
- Eliminated the RSS field from social settings in configuration files and UI schemas. - Updated related documentation and localization files to reflect the removal of RSS support. - Adjusted components to ensure compatibility with the updated social configuration. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
@@ -103,7 +103,7 @@ Notes:
|
||||
|
||||
- `name` / `title` / `description` / `url` / `accentColor`
|
||||
- `author`: `{ name, url, avatar }`
|
||||
- `social`: `{ github?, twitter?, rss? }`
|
||||
- `social`: `{ github?, twitter? }`
|
||||
- `feed`: supports `folo.challenge.feedId` and `userId`
|
||||
- `map`: map providers, e.g. `["maplibre"]`
|
||||
- `mapStyle`: `builtin` or provider-specific style
|
||||
|
||||
@@ -41,6 +41,7 @@ export const MasonryHeaderMasonryItem = ({ style, className }: { style?: React.C
|
||||
siteConfig.social && siteConfig.social.twitter
|
||||
? resolveSocialUrl(siteConfig.social.twitter, { baseUrl: 'https://twitter.com/', stripAt: true })
|
||||
: undefined
|
||||
const hasRss = true
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -76,7 +77,7 @@ export const MasonryHeaderMasonryItem = ({ style, className }: { style?: React.C
|
||||
<h2 className="mt-1 mb-1 text-2xl font-semibold text-gray-900 dark:text-white">{siteConfig.name}</h2>
|
||||
|
||||
{/* Social media links */}
|
||||
{siteConfig.social && (
|
||||
{(githubUrl || twitterUrl || hasRss) && (
|
||||
<div className="mt-1 mb-3 flex items-center justify-center gap-3">
|
||||
{githubUrl && (
|
||||
<a
|
||||
@@ -100,7 +101,7 @@ export const MasonryHeaderMasonryItem = ({ style, className }: { style?: React.C
|
||||
<i className="i-mingcute-twitter-fill text-sm" />
|
||||
</a>
|
||||
)}
|
||||
{siteConfig.social.rss && (
|
||||
{hasRss && (
|
||||
<a
|
||||
href="/feed.xml"
|
||||
target="_blank"
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from '@afilmory/ui'
|
||||
import { useAtom, useSetAtom } from 'jotai'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@afilmory/ui'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useNavigate } from 'react-router'
|
||||
import { Drawer } from 'vaul'
|
||||
|
||||
import { gallerySettingAtom, isCommandPaletteOpenAtom } from '~/atoms/app'
|
||||
import { sessionUserAtom } from '~/atoms/session'
|
||||
import { injectConfig } from '~/config'
|
||||
import { useMobile } from '~/hooks/useMobile'
|
||||
import { authApi } from '~/lib/api/auth'
|
||||
|
||||
import { UserAvatar } from '../../social/comments/UserAvatar'
|
||||
import { ViewPanel } from '../panels/ViewPanel'
|
||||
import { ActionIconButton } from './utils'
|
||||
|
||||
@@ -17,6 +28,7 @@ export const PageHeaderRight = () => {
|
||||
const [gallerySetting] = useAtom(gallerySettingAtom)
|
||||
const setCommandPaletteOpen = useSetAtom(isCommandPaletteOpenAtom)
|
||||
const navigate = useNavigate()
|
||||
const sessionUser = useAtomValue(sessionUserAtom)
|
||||
|
||||
// 计算视图设置是否有自定义配置
|
||||
const hasViewCustomization = gallerySetting.columns !== 'auto' || gallerySetting.sortOrder !== 'desc'
|
||||
@@ -66,6 +78,13 @@ export const PageHeaderRight = () => {
|
||||
</DesktopViewButton>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Auth Section - Only show when useCloud is true */}
|
||||
{injectConfig.useCloud && (
|
||||
<div className="border-border flex items-center gap-1 rounded-full border-[0.5px]">
|
||||
{sessionUser ? <UserMenuButton user={sessionUser} /> : <LoginButton />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -143,3 +162,138 @@ const MobileViewButton = ({
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
// 登录按钮
|
||||
const LoginButton = () => {
|
||||
const { t } = useTranslation()
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const { data: socialProviders } = useQuery({
|
||||
queryKey: ['socialProviders'],
|
||||
queryFn: authApi.getSocialProviders,
|
||||
enabled: isOpen,
|
||||
})
|
||||
|
||||
const handleSignIn = async (provider: string) => {
|
||||
try {
|
||||
const { url } = await authApi.signInSocial(provider)
|
||||
window.location.href = url
|
||||
} catch (error) {
|
||||
console.error('Sign in failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownMenu open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="relative flex size-7 items-center justify-center rounded-full text-white/60 transition-all duration-200 hover:bg-white/10 hover:text-white lg:size-8"
|
||||
title={t('action.login')}
|
||||
>
|
||||
<i className="i-lucide-log-in text-sm lg:text-base" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="min-w-[200px]">
|
||||
<div className="px-2 py-1.5 text-xs text-white/50">{t('comments.chooseProvider')}</div>
|
||||
<DropdownMenuSeparator />
|
||||
{socialProviders?.providers.map((provider) => (
|
||||
<DropdownMenuItem
|
||||
key={provider.id}
|
||||
onClick={() => handleSignIn(provider.id)}
|
||||
icon={<LoginPlatformIcon provider={provider.id} />}
|
||||
>
|
||||
{t('comments.signInWith', { provider: provider.name })}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
|
||||
// 登录平台图标
|
||||
const LoginPlatformIcon = ({ provider }: { provider: string }) => {
|
||||
switch (provider) {
|
||||
case 'github': {
|
||||
return <i className="i-simple-icons-github text-base" />
|
||||
}
|
||||
case 'google': {
|
||||
return (
|
||||
<svg className="size-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 262">
|
||||
<path
|
||||
fill="#4285F4"
|
||||
d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"
|
||||
/>
|
||||
<path
|
||||
fill="#34A853"
|
||||
d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"
|
||||
/>
|
||||
<path
|
||||
fill="#FBBC05"
|
||||
d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"
|
||||
/>
|
||||
<path
|
||||
fill="#EB4335"
|
||||
d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
default: {
|
||||
return <i className="i-lucide-user text-base" />
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 用户菜单按钮
|
||||
const UserMenuButton = ({
|
||||
user,
|
||||
}: {
|
||||
user: { id: string; name?: string | null; image?: string | null; role?: string | null }
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const isAdmin = user.role === 'admin' || user.role === 'superadmin'
|
||||
|
||||
// 如果是 admin,点击头像直接导航到 dashboard
|
||||
if (isAdmin) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="relative flex size-7 items-center justify-center rounded text-white/60 transition-all duration-200 hover:bg-white/10 hover:text-white lg:size-8"
|
||||
title={t('action.dashboard')}
|
||||
onClick={() => (window.location.href = '/platform')}
|
||||
>
|
||||
<UserAvatar image={user.image} name={user.name || user.id} fallback="?" size={28} className="lg:size-8" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
// 非 admin 用户显示菜单
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="relative flex size-7 items-center justify-center rounded text-white/60 transition-all duration-200 hover:bg-white/10 hover:text-white lg:size-8"
|
||||
title={user.name || user.id}
|
||||
>
|
||||
<UserAvatar image={user.image} name={user.name || user.id} fallback="?" size={28} className="lg:size-8" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="min-w-[200px]">
|
||||
<div className="px-2 py-1.5">
|
||||
<div className="text-sm font-medium text-white/90">{user.name || user.id}</div>
|
||||
</div>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
// TODO: Implement sign out
|
||||
window.location.reload()
|
||||
}}
|
||||
icon={<i className="i-lucide-log-out text-base" />}
|
||||
>
|
||||
{t('action.signOut')}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -149,11 +149,6 @@ const enUiSchema = {
|
||||
title: 'GitHub',
|
||||
helper: 'Supports full URLs or usernames.',
|
||||
},
|
||||
rss: {
|
||||
title: 'Expose RSS feed',
|
||||
description: 'Enable to publish an RSS endpoint on the public site.',
|
||||
helper: 'Visitors can subscribe to the latest photos via RSS.',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -148,11 +148,6 @@ const zhCnUiSchema = {
|
||||
title: 'GitHub',
|
||||
helper: '支持完整链接或用户名。',
|
||||
},
|
||||
rss: {
|
||||
title: '生成 RSS 订阅源',
|
||||
description: '启用后将在前台站点暴露 RSS 订阅入口。',
|
||||
helper: '开启后访客可通过 RSS 订阅最新照片。',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -134,25 +134,6 @@ export const DEFAULT_SETTING_DEFINITIONS = {
|
||||
isSensitive: false,
|
||||
schema: z.string().trim(),
|
||||
},
|
||||
'site.social.rss': {
|
||||
isSensitive: false,
|
||||
schema: z
|
||||
.string()
|
||||
.trim()
|
||||
.transform((value) => value.toLowerCase())
|
||||
.superRefine((value, ctx) => {
|
||||
if (value.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (value !== 'true' && value !== 'false') {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'RSS toggle must be either "true" or "false"',
|
||||
})
|
||||
}
|
||||
}),
|
||||
},
|
||||
'site.feed.folo.challenge.feedId': {
|
||||
isSensitive: false,
|
||||
schema: z.string().trim(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { authUsers } from '@afilmory/db'
|
||||
import { DbAccessor } from 'core/database/database.provider'
|
||||
import { BizException, ErrorCode } from 'core/errors'
|
||||
import { normalizeStringToUndefined, parseBoolean } from 'core/helpers/normalize.helper'
|
||||
import { normalizeStringToUndefined } from 'core/helpers/normalize.helper'
|
||||
import { requireTenantContext } from 'core/modules/platform/tenant/tenant.context'
|
||||
import { asc, eq, sql } from 'drizzle-orm'
|
||||
import { injectable } from 'tsyringe'
|
||||
@@ -309,7 +309,6 @@ interface SiteConfigAuthor {
|
||||
interface SiteConfigSocial {
|
||||
twitter?: string
|
||||
github?: string
|
||||
rss?: boolean
|
||||
}
|
||||
|
||||
interface SiteConfigFeed {
|
||||
@@ -408,11 +407,6 @@ function buildSocialConfig(values: SiteSettingValueMap): SiteConfig['social'] |
|
||||
social.github = value
|
||||
})
|
||||
|
||||
const rss = parseBoolean(values['site.social.rss'])
|
||||
if (typeof rss === 'boolean') {
|
||||
social.rss = rss
|
||||
}
|
||||
|
||||
return Object.keys(social).length > 0 ? social : undefined
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ export const SITE_SETTING_KEYS = [
|
||||
'site.accentColor',
|
||||
'site.social.twitter',
|
||||
'site.social.github',
|
||||
'site.social.rss',
|
||||
'site.feed.folo.challenge.feedId',
|
||||
'site.feed.folo.challenge.userId',
|
||||
'site.map.providers',
|
||||
|
||||
@@ -128,18 +128,6 @@ export function createSiteSettingUiSchema(t: UiSchemaTFunction): UiSchema<SiteSe
|
||||
},
|
||||
icon: 'github',
|
||||
},
|
||||
{
|
||||
type: 'field',
|
||||
id: 'site-social-rss',
|
||||
title: t('site.sections.social.groups.channels.fields.rss.title'),
|
||||
description: t('site.sections.social.groups.channels.fields.rss.description'),
|
||||
helperText: t('site.sections.social.groups.channels.fields.rss.helper'),
|
||||
key: 'site.social.rss',
|
||||
component: {
|
||||
type: 'switch',
|
||||
},
|
||||
icon: 'rss',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -11,8 +11,7 @@
|
||||
},
|
||||
"social": {
|
||||
"github": "",
|
||||
"twitter": "",
|
||||
"rss": false
|
||||
"twitter": ""
|
||||
},
|
||||
"feed": {
|
||||
"folo": {
|
||||
@@ -27,4 +26,4 @@
|
||||
],
|
||||
"mapStyle": "builtin",
|
||||
"mapProjection": "mercator"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
- `name`, `title`, `description`, `url`, `accentColor`
|
||||
- `author`: `{ name, url, avatar }`
|
||||
- `social`: `{ github?, twitter?, rss? }`
|
||||
- `social`: `{ github?, twitter? }`
|
||||
- `feed`: optional `folo.challenge.feedId` and `userId`
|
||||
- `map`: e.g. `["maplibre"]`
|
||||
- `mapStyle`: `builtin` or provider style
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
"action.camera.not-found": "No cameras match your search",
|
||||
"action.camera.search": "Search Cameras",
|
||||
"action.columns.setting": "Column Settings",
|
||||
"action.dashboard": "Dashboard",
|
||||
"action.filter.title": "Filter Photos",
|
||||
"action.lens.clear": "Clear",
|
||||
"action.lens.empty": "No lenses available",
|
||||
"action.lens.filter": "Lens Filter",
|
||||
"action.lens.not-found": "No lenses match your search",
|
||||
"action.lens.search": "Search Lenses",
|
||||
"action.login": "Sign In",
|
||||
"action.map.explore": "Map Explore",
|
||||
"action.rating.filter": "Rating Filter",
|
||||
"action.rating.filter-above": "Show {{rating}} stars and above",
|
||||
@@ -27,6 +29,7 @@
|
||||
"action.search.results": "Found {{count}} photos",
|
||||
"action.search.title": "Search Photos",
|
||||
"action.search.unified.title": "Search & Filter",
|
||||
"action.signOut": "Sign Out",
|
||||
"action.sort.mode": "Sort Mode",
|
||||
"action.sort.newest.first": "Newest First",
|
||||
"action.sort.oldest.first": "Oldest First",
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
"action.camera.not-found": "没有相机匹配您的搜索",
|
||||
"action.camera.search": "搜索相机",
|
||||
"action.columns.setting": "列设置",
|
||||
"action.dashboard": "仪表盘",
|
||||
"action.filter.title": "筛选照片",
|
||||
"action.lens.clear": "清除",
|
||||
"action.lens.empty": "暂无镜头",
|
||||
"action.lens.filter": "镜头筛选",
|
||||
"action.lens.not-found": "没有镜头匹配您的搜索",
|
||||
"action.lens.search": "搜索镜头",
|
||||
"action.login": "登录",
|
||||
"action.map.explore": "地图探索",
|
||||
"action.rating.filter": "评分筛选",
|
||||
"action.rating.filter-above": "显示 {{rating}} 星及以上",
|
||||
@@ -27,6 +29,7 @@
|
||||
"action.search.results": "找到 {{count}} 张照片",
|
||||
"action.search.title": "搜索照片",
|
||||
"action.search.unified.title": "搜索和筛选",
|
||||
"action.signOut": "登出",
|
||||
"action.sort.mode": "排序模式",
|
||||
"action.sort.newest.first": "最新优先",
|
||||
"action.sort.oldest.first": "最早优先",
|
||||
|
||||
@@ -39,7 +39,6 @@ interface Author {
|
||||
interface Social {
|
||||
twitter?: string
|
||||
github?: string
|
||||
rss?: boolean
|
||||
}
|
||||
|
||||
const defaultConfig: SiteConfig = {
|
||||
|
||||
Reference in New Issue
Block a user