feat: add group background image in invite

and move entry image from entry to all
pull/105/head
moonrailgun 2 years ago
parent a765bb0248
commit 947d05697a

@ -3,10 +3,13 @@ import { Image as AntdImage, ImageProps as AntdImageProps } from 'antd';
export let imageUrlParser = (url: string) => url;
const fallback =
'data:image/png;base64,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';
export const Image: React.FC<AntdImageProps> = React.memo((props) => {
return (
<AntdImage
fallback="data:image/png;base64,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"
fallback={fallback}
preview={false}
loading="lazy"
{...props}

@ -13,6 +13,7 @@
"k1596c75c": "Only allow specified users to speak",
"k1704ea49": "Install",
"k17777797": "The panel is provided by the plugin",
"k17acf2a8": "Personalized configuration group background",
"k18580d81": "Create a link and send it to external friends",
"k186fec4": "Plugin failed to load",
"k1885734a": "Effective after refreshing the page",
@ -221,6 +222,7 @@
"ka2c48894": "Customize your group",
"ka2ed2b61": "Are you sure you want to do this?",
"ka30dd0bc": "This action cannot be undo",
"ka35f4202": "Group Background",
"ka39b3032": "1 day",
"ka49ec177": "Input somthing",
"ka4cebef8": "New Role",
@ -327,6 +329,7 @@
"kdef84ee6": "Plugin",
"kdf6e53ca": "Converse does not have permission",
"kdf89681f": "Add friend nickname",
"ke0131e71": "Recommended aspect: 16:9 | Recommended size: 1280x720",
"ke0161a83": "Reset to default address",
"ke040edce": "No rendering method of this type found",
"ke071c620": "Allow members to manage users, such as banning, removing users, etc.",

@ -13,6 +13,7 @@
"k1596c75c": "仅允许指定用户发言",
"k1704ea49": "安装",
"k17777797": "该面板由插件提供",
"k17acf2a8": "个性化配置群组背景",
"k18580d81": "创建链接并发送给外部好友",
"k186fec4": "插件加载失败",
"k1885734a": "刷新页面后生效",
@ -221,6 +222,7 @@
"ka2c48894": "自定义你的群组",
"ka2ed2b61": "确认要进行该操作么?",
"ka30dd0bc": "该操作无法被撤回",
"ka35f4202": "群组背景",
"ka39b3032": "1天",
"ka49ec177": "输入一些什么",
"ka4cebef8": "新身份组",
@ -327,6 +329,7 @@
"kdef84ee6": "插件",
"kdf6e53ca": "会话没有权限",
"kdf89681f": "添加好友昵称",
"ke0131e71": "建议比例: 16:9 | 建议大小: 1280x720",
"ke0161a83": "重置为默认地址",
"ke040edce": "没有找到该类型的渲染方式",
"ke071c620": "允许成员管理用户,如禁言、移除用户等操作",

@ -9,6 +9,9 @@ export enum GroupPanelType {
export const groupConfigNames = [
// 隐藏群组成员标识位
'hideGroupMemberDiscriminator',
// 群组背景图
'groupBackgroundImage',
] as const;
export type GroupConfigNames = (typeof groupConfigNames)[number] | string; // string is plugin config
@ -86,6 +89,7 @@ export interface GroupBasicInfo {
avatar?: string;
owner: string;
memberCount: number;
backgroundImage?: string;
}
export interface GroupInvite {

@ -7,6 +7,7 @@ import {
Routes,
} from 'react-router-dom';
import {
parseUrlStr,
sharedEvent,
TcProvider,
useColorScheme,
@ -95,14 +96,25 @@ AppContainer.displayName = 'AppContainer';
const AppHeader: React.FC = React.memo(() => {
const { language } = useLanguage();
const { serverName } = useGlobalConfigStore((state) => ({
const { serverName, serverEntryImage } = useGlobalConfigStore((state) => ({
serverName: state.serverName,
serverEntryImage: state.serverEntryImage,
}));
return (
<Helmet>
<meta httpEquiv="Content-Language" content={language} />
<title>{serverName}</title>
{serverEntryImage && (
<style type="text/css">
{`
#tailchat-app {
--tc-background-image: url(${parseUrlStr(serverEntryImage)});
}
`}
</style>
)}
</Helmet>
);
});

@ -3,15 +3,18 @@ import {
model,
showSuccessToasts,
t,
UploadFileResult,
useAsyncRequest,
useGroupInfo,
} from 'tailchat-shared';
import { Image } from 'tailchat-design';
import { Loading } from '@/components/Loading';
import { FullModalField } from '@/components/FullModal/Field';
import { FullModalCommonTitle } from '@/components/FullModal/CommonTitle';
import { Switch } from 'antd';
import { pluginGroupConfigItems } from '@/plugin/common';
import { ensurePluginNamePrefix } from '@/utils/plugin-helper';
import { ImageUploader } from '@/components/ImageUploader';
export const GroupConfig: React.FC<{
groupId: string;
@ -51,6 +54,30 @@ export const GroupConfig: React.FC<{
}
/>
<FullModalField
title={t('群组背景')}
tip={t('个性化配置群组背景')}
content={
<>
<ImageUploader
aspect={16 / 9}
onUploadSuccess={function (fileInfo: UploadFileResult): void {
handleModifyConfig('groupBackgroundImage', fileInfo.url);
}}
>
<Image
wrapperClassName="block"
style={{ width: 640, height: 360 }}
src={config['groupBackgroundImage']}
/>
</ImageUploader>
<div className="text-xs opacity-80">
{t('建议比例: 16:9 | 建议大小: 1280x720')}
</div>
</>
}
/>
{pluginGroupConfigItems.map((item) => {
const name = ensurePluginNamePrefix(item.name);
return (

@ -8,16 +8,10 @@ import { RegisterView } from './RegisterView';
import { useRecordMeasure } from '@/utils/measure-helper';
import { GuestView } from './GuestView';
import { ForgetPasswordView } from './ForgetPasswordView';
import { Helmet } from 'react-helmet';
import { parseUrlStr, useGlobalConfigStore } from 'tailchat-shared';
const EntryRoute = React.memo(() => {
useRecordMeasure('appEntryRenderStart');
const serverEntryImage = useGlobalConfigStore(
(state) => state.serverEntryImage
);
return (
<div className="h-full flex flex-row">
<div
@ -39,18 +33,6 @@ const EntryRoute = React.memo(() => {
</Routes>
</div>
{serverEntryImage && (
<Helmet>
<style type="text/css">
{`
#tailchat-app {
--tc-background-image: url(${parseUrlStr(serverEntryImage)});
}
`}
</style>
</Helmet>
)}
<div className="flex-1 mobile:hidden tc-background" />
</div>
);

@ -7,6 +7,7 @@ import React from 'react';
import {
getCachedGroupInviteInfo,
getGroupBasicInfo,
GroupBasicInfo,
showErrorToasts,
t,
useAsync,
@ -15,6 +16,7 @@ import { JoinBtn } from './JoinBtn';
interface Props {
inviteCode: string;
onLoadInfo: (groupInfo: GroupBasicInfo) => void;
}
export const InviteInfo: React.FC<Props> = React.memo((props) => {
const { inviteCode } = props;
@ -30,6 +32,8 @@ export const InviteInfo: React.FC<Props> = React.memo((props) => {
throw new Error(t('找不到群组信息'));
}
props.onLoadInfo(groupBasicInfo);
return {
group: groupBasicInfo,
creator: invite.creator,

@ -1,21 +1,46 @@
import React from 'react';
import React, { useMemo, useState } from 'react';
import { useParams } from 'react-router';
import { InviteInfo } from './InviteInfo';
import { PortalHost } from '@/components/Portal';
import { useRecordMeasure } from '@/utils/measure-helper';
import { parseUrlStr } from 'tailchat-shared';
/**
*
*/
const InviteRoute: React.FC = React.memo(() => {
const { inviteCode = '' } = useParams<{ inviteCode: string }>();
const [groupBackground, setGroupBackground] = useState('');
useRecordMeasure('appInviteRenderStart');
const style: React.CSSProperties = useMemo(
() =>
groupBackground
? {
backgroundImage: `url(${parseUrlStr(groupBackground)})`,
}
: {
backgroundImage: 'var(--tc-background-image)',
},
[groupBackground]
);
return (
<PortalHost>
<div className="h-full w-full bg-gray-600 flex justify-center items-center tc-background">
<div
className="h-full w-full bg-gray-600 flex justify-center items-center bg-center bg-cover bg-no-repeat"
style={style}
>
<div className="w-96 p-4 rounded-lg shadow-lg bg-black bg-opacity-60 text-center">
<InviteInfo inviteCode={inviteCode} />
<InviteInfo
inviteCode={inviteCode}
onLoadInfo={(info) => {
if (info.backgroundImage) {
setGroupBackground(info.backgroundImage);
}
}}
/>
</div>
</div>
</PortalHost>

@ -55,6 +55,7 @@ export type GroupBaseInfo = Pick<
'name' | 'avatar' | 'owner' | 'description'
> & {
memberCount: number;
backgroundImage?: string;
};
/**

@ -350,6 +350,7 @@ class GroupService extends TcService {
owner: 1,
description: 1,
members: 1,
config: 1,
})
.exec();
@ -358,6 +359,7 @@ class GroupService extends TcService {
}
const groupMemberCount = group.members.length;
const backgroundImage = group.config['groupBackgroundImage'];
return {
name: group.name,
@ -365,6 +367,7 @@ class GroupService extends TcService {
owner: String(group.owner),
description: group.description ?? '',
memberCount: groupMemberCount,
backgroundImage: backgroundImage,
};
}

Loading…
Cancel
Save