feat(B07,B08): 워크플로 순서 교환 — 상세설계를 수량산출 앞으로
횡단설계(B06) 다음을 상세설계 → 수량산출 → 설계도서 순으로 재배열하고, 폴더 번호가 흐름과 일치하도록 이름을 맞바꾼다. - B08_DesignDetail → B07_DesignDetail, B07_Quantity → B08_Quantity (파일 접두어·식별자·라우트·locale 키 전량 스왑) - STAGE_KEYS 4=DESIGN_DETAIL, 5=QUANTITY 스왑 + 라우터 stage 리터럴 교체 - CAD 마운트 /b08-cad → /b07-cad (main.py·vite proxy·iframe URL), openwebcad Toolbar 라벨 B07로 수정 후 재빌드 - 유지: openwebcad postMessage 프로토콜 aislo:b08:*·패키지명(내부 식별자) - 기존 프로젝트 storage 폴더 rename + project_manifest 갱신, DB project_workflow_stages stage_no 4↔5 행 스왑 완료 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import type {CSSProperties, FC, ReactNode} from 'react';
|
||||
import useLocalStorageState from 'use-local-storage-state';
|
||||
import {LOCAL_STORAGE_KEY} from '../App.types.ts';
|
||||
import {keyboardHandler} from '../helpers/keyboard-handler.ts';
|
||||
import {Button} from './Button.tsx';
|
||||
import {Icon, IconName} from './Icon/Icon.tsx';
|
||||
|
||||
interface DropdownButtonProps {
|
||||
label?: string;
|
||||
title?: string;
|
||||
iconName?: IconName;
|
||||
iconComponent?: ReactNode;
|
||||
active?: boolean;
|
||||
onClick?: () => void;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
buttonStyle?: CSSProperties;
|
||||
dataId: string;
|
||||
children?: ReactNode;
|
||||
defaultOpen?: boolean;
|
||||
}
|
||||
|
||||
export const DropdownButton: FC<DropdownButtonProps> = ({
|
||||
label,
|
||||
title,
|
||||
iconName,
|
||||
iconComponent,
|
||||
className,
|
||||
style,
|
||||
buttonStyle,
|
||||
dataId,
|
||||
children,
|
||||
defaultOpen = false,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useLocalStorageState<boolean>(
|
||||
`${LOCAL_STORAGE_KEY.DROPDOWN}___${dataId}`,
|
||||
{ defaultValue: defaultOpen }
|
||||
);
|
||||
|
||||
const classParts = [
|
||||
'flex flex-col gap-2 relative',
|
||||
className || '',
|
||||
isOpen ? ' bg-slate-900' : '',
|
||||
];
|
||||
return (
|
||||
<div className={classParts.join(' ')} style={style} data-id={dataId}>
|
||||
<Button
|
||||
iconName={iconName}
|
||||
iconComponent={iconComponent}
|
||||
label={label}
|
||||
title={title}
|
||||
active={isOpen}
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
style={buttonStyle}
|
||||
className={'w-full data-[active=true]:bg-blue-950 data-[active=true]:text-white'}
|
||||
/>
|
||||
<Icon name={IconName.SolidDownSmall} className={'absolute top-2.5 right-1 text-blue-700'} />
|
||||
{isOpen && (
|
||||
<div
|
||||
className="flex flex-row flex-wrap max-w-72 gap-1 pl-1 pb-6"
|
||||
onClick={() => setIsOpen(false)}
|
||||
onKeyUp={keyboardHandler(() => setIsOpen(false))}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user