收口前端平台组件库能力
新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件 迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome 补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
This commit is contained in:
@@ -6,11 +6,15 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
export type SquareImageCropRect = {
|
||||
x: number;
|
||||
y: number;
|
||||
size: number;
|
||||
};
|
||||
import { PlatformActionButton } from './PlatformActionButton';
|
||||
import { PlatformModalCloseButton } from './PlatformModalCloseButton';
|
||||
import { PlatformStatusMessage } from './PlatformStatusMessage';
|
||||
import {
|
||||
clampNumber,
|
||||
clampSquareImageCropRect,
|
||||
getSquareCropSizeBounds,
|
||||
type SquareImageCropRect,
|
||||
} from './squareImageCropModel';
|
||||
|
||||
export type SquareImageCropModalLabels = {
|
||||
title: string;
|
||||
@@ -98,44 +102,6 @@ const SQUARE_CROP_RESIZE_HANDLES: Array<{
|
||||
},
|
||||
];
|
||||
|
||||
function clampNumber(value: number, min: number, max: number) {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
|
||||
function getSquareCropSizeBounds(imageSize: { width: number; height: number }) {
|
||||
const maxSize = Math.max(1, Math.min(imageSize.width, imageSize.height));
|
||||
const minSize = Math.min(maxSize, Math.max(48, maxSize * 0.18));
|
||||
|
||||
return { minSize, maxSize };
|
||||
}
|
||||
|
||||
export function buildCenteredSquareImageCropRect(imageSize: {
|
||||
width: number;
|
||||
height: number;
|
||||
}): SquareImageCropRect {
|
||||
const size = Math.max(1, Math.min(imageSize.width, imageSize.height));
|
||||
|
||||
return {
|
||||
x: Math.max(0, (imageSize.width - size) / 2),
|
||||
y: Math.max(0, (imageSize.height - size) / 2),
|
||||
size,
|
||||
};
|
||||
}
|
||||
|
||||
export function clampSquareImageCropRect(
|
||||
imageSize: { width: number; height: number },
|
||||
crop: SquareImageCropRect,
|
||||
): SquareImageCropRect {
|
||||
const { minSize, maxSize } = getSquareCropSizeBounds(imageSize);
|
||||
const size = clampNumber(crop.size, minSize, maxSize);
|
||||
|
||||
return {
|
||||
x: clampNumber(crop.x, 0, Math.max(0, imageSize.width - size)),
|
||||
y: clampNumber(crop.y, 0, Math.max(0, imageSize.height - size)),
|
||||
size,
|
||||
};
|
||||
}
|
||||
|
||||
function buildSquareCropPreviewStyle(
|
||||
crop: SquareImageCropRect,
|
||||
imageSize: { width: number; height: number },
|
||||
@@ -354,14 +320,12 @@ export function SquareImageCropModal({
|
||||
<div id={titleId} className="text-base font-black">
|
||||
{labels.title}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={labels.close}
|
||||
<PlatformModalCloseButton
|
||||
label={labels.close}
|
||||
variant="profileCompact"
|
||||
onClick={onClose}
|
||||
className="platform-profile-icon-button flex h-8 w-8 items-center justify-center rounded-full"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
icon="×"
|
||||
/>
|
||||
</div>
|
||||
<div className="px-5 py-5">
|
||||
<div
|
||||
@@ -416,26 +380,24 @@ export function SquareImageCropModal({
|
||||
</div>
|
||||
</div>
|
||||
{error ? (
|
||||
<div className="mt-4 rounded-2xl border border-[var(--platform-button-danger-border)] bg-[var(--platform-button-danger-fill)] px-3 py-2 text-sm text-[var(--platform-button-danger-text)]">
|
||||
<PlatformStatusMessage
|
||||
tone="error"
|
||||
surface="profile"
|
||||
className="mt-4 rounded-2xl"
|
||||
>
|
||||
{error}
|
||||
</div>
|
||||
</PlatformStatusMessage>
|
||||
) : null}
|
||||
<div className="mt-5 grid grid-cols-2 gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="platform-button platform-button--secondary justify-center"
|
||||
>
|
||||
<PlatformActionButton tone="secondary" onClick={onClose}>
|
||||
{labels.cancel}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
</PlatformActionButton>
|
||||
<PlatformActionButton
|
||||
onClick={onSubmit}
|
||||
disabled={isSaving}
|
||||
className="platform-button platform-button--primary justify-center disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
{isSaving ? labels.saving : labels.submit}
|
||||
</button>
|
||||
</PlatformActionButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user