mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
fix(selfhost): branding image origins and theme colour (#3389)
This commit is contained in:
1 parent
cca8227ca6
commit
edc913096a
27 files changed
+724
-49
No files matched your search
@@ -161,10 +161,10 @@ const STEP_NAVIGATION_LOCK_MS = 320;
|
||||
|
||||
const BRANDING_ASSET_KINDS: ReadonlyArray<SetupBrandingAssetKind> = ['icon', 'symbol', 'logo', 'wordmark', 'favicon'];
|
||||
|
||||
function hexToNumber(value: string | null): number {
|
||||
if (!value) return 0;
|
||||
function hexToNumber(value: string | null): number | null {
|
||||
if (!value) return null;
|
||||
const match = /^#?([0-9a-fA-F]{6})$/.exec(value.trim());
|
||||
if (!match) return 0;
|
||||
if (!match) return null;
|
||||
return parseInt(match[1], 16) >>> 0;
|
||||
}
|
||||
|
||||
@@ -463,7 +463,7 @@ export const SelfHostedSetupWizardGate = observer(() => {
|
||||
const [creatingRecoveryKit, setCreatingRecoveryKit] = useState(false);
|
||||
|
||||
const [productName, setProductName] = useState('');
|
||||
const [themeColor, setThemeColor] = useState(0);
|
||||
const [themeColor, setThemeColor] = useState<number | null>(null);
|
||||
const [registrationMode, setRegistrationMode] = useState<RegistrationMode>('open');
|
||||
const [singleCommunityEnabled, setSingleCommunityEnabled] = useState(false);
|
||||
const [singleCommunityName, setSingleCommunityName] = useState('');
|
||||
@@ -902,7 +902,7 @@ export const SelfHostedSetupWizardGate = observer(() => {
|
||||
app_public: {
|
||||
branding: {
|
||||
product_name: productNameTrimmed,
|
||||
theme_color: numberToHexColor(themeColor),
|
||||
theme_color: themeColor === null ? null : numberToHexColor(themeColor),
|
||||
},
|
||||
setup: {configured: true},
|
||||
},
|
||||
|
||||
@@ -34,6 +34,7 @@ import type React from 'react';
|
||||
import {useCallback} from 'react';
|
||||
|
||||
const PUSH_RELAY_NOTICE_URL = 'https://fluxer.com/push-relay';
|
||||
const DEFAULT_THEME_COLOR = 0x4641d9;
|
||||
|
||||
export type RegistrationMode = 'open' | 'approval' | 'closed';
|
||||
export type PremiumMode = 'mirror' | 'everyone';
|
||||
@@ -844,11 +845,11 @@ export const BrandingStep = observer(
|
||||
}: {
|
||||
productName: string;
|
||||
productNameError: boolean;
|
||||
themeColor: number;
|
||||
themeColor: number | null;
|
||||
assets: ReadonlyArray<BrandingAssetState>;
|
||||
disabled: boolean;
|
||||
onProductNameChange: (value: string) => void;
|
||||
onThemeColorChange: (value: number) => void;
|
||||
onThemeColorChange: (value: number | null) => void;
|
||||
onUploadAsset: (kind: SetupBrandingAssetKind) => void;
|
||||
onClearAsset: (kind: SetupBrandingAssetKind) => void;
|
||||
}) => {
|
||||
@@ -873,8 +874,11 @@ export const BrandingStep = observer(
|
||||
/>
|
||||
<ColorPickerField
|
||||
label={i18n._(THEME_COLOR_LABEL_DESCRIPTOR)}
|
||||
value={themeColor}
|
||||
value={themeColor ?? DEFAULT_THEME_COLOR}
|
||||
onChange={onThemeColorChange}
|
||||
defaultValue={DEFAULT_THEME_COLOR}
|
||||
isDefaultValue={themeColor === null}
|
||||
onReset={() => onThemeColorChange(null)}
|
||||
disabled={disabled}
|
||||
data-flx="app.self-hosted-setup-wizard-gate.theme-color-field"
|
||||
/>
|
||||
|
||||
@@ -11,6 +11,10 @@ export const NATIVE_NOTIFICATION_ICON_CSS_SIZE: MediaProxyImageSize = 128;
|
||||
export function getNotificationIconURL(user: Pick<User, 'id' | 'avatar'>, guildId?: string | null): string {
|
||||
const member = guildId ? GuildMembers.getMember(guildId, user.id) : null;
|
||||
const nativeIcon = isDesktop();
|
||||
const systemAvatarUrl = AvatarUtils.getSystemUserBrandingAvatarURL(user.id);
|
||||
if (systemAvatarUrl !== null) {
|
||||
return systemAvatarUrl;
|
||||
}
|
||||
if (guildId && member) {
|
||||
return nativeIcon
|
||||
? AvatarUtils.getGuildMemberNotificationAvatarURL({
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import * as ColorUtils from '@app/features/theme/utils/ColorUtils';
|
||||
import type {User} from '@app/features/user/models/User';
|
||||
import {getDefaultAvatarPrimaryColor} from '@app/features/user/utils/AvatarUtils';
|
||||
import {getDefaultAvatarPrimaryColor, getSystemUserBrandingColor} from '@app/features/user/utils/AvatarUtils';
|
||||
import {DEFAULT_ACCENT_COLOR} from '@fluxer/constants/src/AppConstants';
|
||||
|
||||
type RawAccentColor = number | null | undefined;
|
||||
@@ -19,6 +19,10 @@ export function getUserAccentColor(
|
||||
profileAccentColor?: RawAccentColor,
|
||||
fallback = DEFAULT_ACCENT_COLOR,
|
||||
): string {
|
||||
const systemColor = user ? getSystemUserBrandingColor(user.id) : null;
|
||||
if (systemColor) {
|
||||
return systemColor;
|
||||
}
|
||||
const profileColor = getAccentColorHex(profileAccentColor);
|
||||
if (profileColor) {
|
||||
return profileColor;
|
||||
|
||||
+2
-11
@@ -1,11 +1,9 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
|
||||
import {getUserAccentColor} from '@app/features/theme/utils/AccentColorUtils';
|
||||
import {ProfileBody} from '@app/features/user/components/modals/user_profile_modal/ProfileBody';
|
||||
import {ProfileMediaHeader} from '@app/features/user/components/modals/user_profile_modal/ProfileMediaHeader';
|
||||
import type {ProfileModalContentProps} from '@app/features/user/components/modals/user_profile_modal/UserProfileModalShared';
|
||||
import * as AvatarUtils from '@app/features/user/utils/AvatarUtils';
|
||||
import * as ProfileDisplayUtils from '@app/features/user/utils/ProfileDisplayUtils';
|
||||
import {resolveProfileGuildMembership, toProfileDisplayContext} from '@app/features/user/utils/ProfileGuildMembership';
|
||||
import {FLUXERBOT_ID} from '@fluxer/constants/src/AppConstants';
|
||||
@@ -30,11 +28,7 @@ export const ProfileModalContent: React.FC<ProfileModalContentProps> = observer(
|
||||
}) => {
|
||||
const effectiveProfile = profile?.getEffectiveProfile() ?? null;
|
||||
const isSystemUser = user.id === FLUXERBOT_ID;
|
||||
const systemThemeColor =
|
||||
isSystemUser && RuntimeConfig.isSelfHosted()
|
||||
? RuntimeConfig.getSnapshotOrNull()?.appPublic.branding.theme_color
|
||||
: null;
|
||||
const bannerColor = systemThemeColor ?? getUserAccentColor(user, effectiveProfile?.accent_color);
|
||||
const bannerColor = getUserAccentColor(user, effectiveProfile?.accent_color);
|
||||
const membership = resolveProfileGuildMembership(profile);
|
||||
const profileContext = useMemo<ProfileDisplayUtils.ProfileDisplayContext>(
|
||||
() =>
|
||||
@@ -46,13 +40,10 @@ export const ProfileModalContent: React.FC<ProfileModalContentProps> = observer(
|
||||
}),
|
||||
[user, profile, membership],
|
||||
);
|
||||
const {avatarUrl: profileAvatarUrl, hoverAvatarUrl: profileHoverAvatarUrl} = useMemo(
|
||||
const {avatarUrl, hoverAvatarUrl} = useMemo(
|
||||
() => ProfileDisplayUtils.getProfileAvatarUrls(profileContext, previewOverrides, MEDIA_PROXY_AVATAR_SIZE_PROFILE),
|
||||
[profileContext, previewOverrides],
|
||||
);
|
||||
const systemAvatarUrl = AvatarUtils.getSystemUserBrandingAvatarURL(user.id);
|
||||
const avatarUrl = systemAvatarUrl ?? profileAvatarUrl;
|
||||
const hoverAvatarUrl = systemAvatarUrl ?? profileHoverAvatarUrl;
|
||||
const {bannerUrl, hoverBannerUrl} = useMemo(
|
||||
() =>
|
||||
ProfileDisplayUtils.getProfileBannerUrls(
|
||||
|
||||
@@ -82,6 +82,11 @@ export function getSystemUserBrandingAvatarURL(userId: string): string | null {
|
||||
return branding?.icon_url ?? branding?.logo_url ?? null;
|
||||
}
|
||||
|
||||
export function getSystemUserBrandingColor(userId: string): string | null {
|
||||
if (userId !== FLUXERBOT_ID || !RuntimeConfig.isSelfHosted()) return null;
|
||||
return RuntimeConfig.getSnapshotOrNull()?.appPublic.branding.theme_color ?? null;
|
||||
}
|
||||
|
||||
export function getDefaultAvatarPrimaryColor(id: string) {
|
||||
return getSharedDefaultAvatarPrimaryColor(id);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@ function getProfileAvatarUrl(
|
||||
if (previewAvatarUrl) {
|
||||
return previewAvatarUrl;
|
||||
}
|
||||
const systemAvatarUrl = AvatarUtils.getSystemUserBrandingAvatarURL(user.id);
|
||||
if (systemAvatarUrl !== null) {
|
||||
return systemAvatarUrl;
|
||||
}
|
||||
if (!ignoreGuildAvatar && guildId && guildMember) {
|
||||
return AvatarUtils.getGuildMemberDisplayAvatarURL({
|
||||
guildId,
|
||||
|
||||
Reference in new issue
Block a user