@shepai/cli 1.60.0 → 1.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/presentation/web/components/common/action-button/action-button.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/action-button/action-button.js +7 -1
- package/dist/src/presentation/web/components/common/action-button/action-button.stories.d.ts +1 -1
- package/dist/src/presentation/web/components/common/action-button/action-button.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/action-button/action-button.stories.js +1 -1
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.js +10 -1
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.stories.d.ts +20 -0
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.stories.js +68 -0
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js +23 -2
- package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.js +13 -2
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.js +16 -3
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.d.ts +1 -1
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.js +1 -1
- package/dist/src/presentation/web/components/common/sidebar-collapse-toggle/sidebar-collapse-toggle.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/sidebar-collapse-toggle/sidebar-collapse-toggle.js +14 -1
- package/dist/src/presentation/web/components/common/sidebar-collapse-toggle/sidebar-collapse-toggle.stories.d.ts +2 -0
- package/dist/src/presentation/web/components/common/sidebar-collapse-toggle/sidebar-collapse-toggle.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/sidebar-collapse-toggle/sidebar-collapse-toggle.stories.js +2 -0
- package/dist/src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.js +4 -1
- package/dist/src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.stories.d.ts +1 -0
- package/dist/src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.stories.js +1 -0
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.js +14 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.d.ts +1 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.js +1 -1
- package/dist/src/presentation/web/components/common/theme-toggle/theme-toggle.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/theme-toggle/theme-toggle.js +13 -0
- package/dist/src/presentation/web/components/common/theme-toggle/theme-toggle.stories.d.ts +2 -0
- package/dist/src/presentation/web/components/common/theme-toggle/theme-toggle.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/theme-toggle/theme-toggle.stories.js +2 -0
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +2 -2
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +7 -13
- package/dist/src/presentation/web/hooks/use-notifications.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-notifications.js +18 -18
- package/dist/src/presentation/web/hooks/use-sound-action.d.ts +100 -0
- package/dist/src/presentation/web/hooks/use-sound-action.d.ts.map +1 -0
- package/dist/src/presentation/web/hooks/use-sound-action.js +42 -0
- package/dist/src/presentation/web/hooks/use-sound-action.stories.d.ts +6 -0
- package/dist/src/presentation/web/hooks/use-sound-action.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/hooks/use-sound-action.stories.js +61 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/cache/.previewinfo +1 -1
- package/web/.next/cache/.rscinfo +1 -1
- package/web/.next/cache/.tsbuildinfo +1 -1
- package/web/.next/cache/config.json +3 -3
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +1 -1
- package/web/.next/required-server-files.json +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/page/server-reference-manifest.json +14 -14
- package/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2395adc6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2395adc6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__87fda958._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__87fda958._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +4 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__b6839c3f._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__b6839c3f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__da0ade1f._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__da0ade1f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fbc89707._.js +1 -1
- package/web/.next/server/chunks/ssr/{_34627374._.js → _d3711354._.js} +2 -2
- package/web/.next/server/chunks/ssr/_d3711354._.js.map +1 -0
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +15 -15
- package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +14 -14
- package/web/.next/standalone/src/presentation/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2395adc6._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__87fda958._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +4 -4
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__b6839c3f._.js +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__da0ade1f._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__fbc89707._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{_34627374._.js → _d3711354._.js} +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +15 -15
- package/web/.next/standalone/src/presentation/web/components/common/action-button/action-button.stories.tsx +1 -1
- package/web/.next/standalone/src/presentation/web/components/common/action-button/action-button.tsx +9 -1
- package/web/.next/standalone/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.stories.tsx +82 -0
- package/web/.next/standalone/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.tsx +16 -2
- package/web/.next/standalone/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx +29 -3
- package/web/.next/standalone/src/presentation/web/components/common/feature-drawer/feature-drawer.tsx +14 -2
- package/web/.next/standalone/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.tsx +1 -1
- package/web/.next/standalone/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.tsx +17 -4
- package/web/.next/standalone/src/presentation/web/components/common/sidebar-collapse-toggle/sidebar-collapse-toggle.stories.tsx +2 -0
- package/web/.next/standalone/src/presentation/web/components/common/sidebar-collapse-toggle/sidebar-collapse-toggle.tsx +14 -1
- package/web/.next/standalone/src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.stories.tsx +1 -0
- package/web/.next/standalone/src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.tsx +6 -1
- package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.tsx +1 -1
- package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.tsx +14 -1
- package/web/.next/standalone/src/presentation/web/components/common/theme-toggle/theme-toggle.stories.tsx +2 -0
- package/web/.next/standalone/src/presentation/web/components/common/theme-toggle/theme-toggle.tsx +14 -0
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +2 -2
- package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +7 -12
- package/web/.next/standalone/src/presentation/web/hooks/use-notifications.ts +20 -19
- package/web/.next/standalone/src/presentation/web/hooks/use-sound-action.stories.tsx +107 -0
- package/web/.next/standalone/src/presentation/web/hooks/use-sound-action.ts +53 -0
- package/web/.next/standalone/src/presentation/web/server.js +1 -1
- package/web/.next/static/chunks/{bac5122e95f5c7eb.js → 13664c029245afc8.js} +1 -1
- package/web/.next/static/chunks/45f510f84c7c417d.css +2 -0
- package/web/.next/static/chunks/8e4c719503d9387e.js +1 -0
- package/web/.next/static/chunks/cd44f06f18e3425a.js +10 -0
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/web/.next/server/chunks/ssr/_34627374._.js.map +0 -1
- package/web/.next/static/chunks/1fe24572a810eafa.js +0 -10
- package/web/.next/static/chunks/7d3c5ae8f47e74cd.js +0 -1
- package/web/.next/static/chunks/8b2879f911a05b55.css +0 -2
- /package/web/.next/static/{enyZhg62FqP6oInxg1T3h → 2z-UoCok36_D1hh1-N88G}/_buildManifest.js +0 -0
- /package/web/.next/static/{enyZhg62FqP6oInxg1T3h → 2z-UoCok36_D1hh1-N88G}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{enyZhg62FqP6oInxg1T3h → 2z-UoCok36_D1hh1-N88G}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-button.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/action-button/action-button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"action-button.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/action-button/action-button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM/C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,UAAU,CAAC;IACjB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yCAAyC;IACzC,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,MAAM,CAAC;IACjF,iCAAiC;IACjC,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;CACpF;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,OAAO,EACP,OAAO,EACP,KAAK,EACL,IAAI,EAAE,IAAI,EACV,QAAgB,EAChB,OAAmB,EACnB,IAAW,GACZ,EAAE,iBAAiB,2CAkCnB"}
|
|
@@ -3,8 +3,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { Loader2, CircleAlert } from 'lucide-react';
|
|
4
4
|
import { cn } from '../../../lib/utils.js';
|
|
5
5
|
import { Button } from '../../ui/button.js';
|
|
6
|
+
import { useSoundAction } from '../../../hooks/use-sound-action.js';
|
|
6
7
|
export function ActionButton({ label, onClick, loading, error, icon: Icon, iconOnly = false, variant = 'outline', size = 'sm', }) {
|
|
7
|
-
|
|
8
|
+
const clickSound = useSoundAction('click');
|
|
9
|
+
const handleClick = () => {
|
|
10
|
+
clickSound.play();
|
|
11
|
+
onClick();
|
|
12
|
+
};
|
|
13
|
+
return (_jsxs(Button, { variant: variant, size: size, "aria-label": label, disabled: loading, onClick: handleClick, className: cn('gap-1.5', error && 'text-destructive hover:text-destructive', !error &&
|
|
8
14
|
iconOnly &&
|
|
9
15
|
variant === 'ghost' &&
|
|
10
16
|
'text-muted-foreground cursor-pointer rounded-full transition-colors hover:text-blue-500'), children: [loading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : error ? (_jsx(CircleAlert, { className: "size-4" })) : (_jsx(Icon, { className: "size-4" })), iconOnly ? null : label] }));
|
package/dist/src/presentation/web/components/common/action-button/action-button.stories.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { ActionButton } from './action-button.js';
|
|
|
3
3
|
declare const meta: Meta<typeof ActionButton>;
|
|
4
4
|
export default meta;
|
|
5
5
|
type Story = StoryObj<typeof ActionButton>;
|
|
6
|
-
/** Default labeled button with outline variant. */
|
|
6
|
+
/** Default labeled button with outline variant. Plays "click" sound on press. */
|
|
7
7
|
export declare const Default: Story;
|
|
8
8
|
/** Loading state — spinner replaces icon, button is disabled. */
|
|
9
9
|
export declare const Loading: Story;
|
package/dist/src/presentation/web/components/common/action-button/action-button.stories.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-button.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/action-button/action-button.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,YAAY,CAanC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,YAAY,CAAC,CAAC;AAM3C,
|
|
1
|
+
{"version":3,"file":"action-button.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/action-button/action-button.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,YAAY,CAanC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,YAAY,CAAC,CAAC;AAM3C,iFAAiF;AACjF,eAAO,MAAM,OAAO,EAAE,KAIrB,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,OAAO,EAAE,KAKrB,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,KAAK,EAAE,KAKnB,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,QAAQ,EAAE,KAOtB,CAAC;AAEF,+BAA+B;AAC/B,eAAO,MAAM,eAAe,EAAE,KAQ7B,CAAC;AAEF,6BAA6B;AAC7B,eAAO,MAAM,aAAa,EAAE,KAQ3B,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,YAAY,EAAE,KAO1B,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,kBAAkB,EAAE,KAahC,CAAC;AAEF,oHAAoH;AACpH,eAAO,MAAM,mBAAmB,EAAE,KAmCjC,CAAC"}
|
|
@@ -19,7 +19,7 @@ export default meta;
|
|
|
19
19
|
function noop() {
|
|
20
20
|
// intentional no-op for stories
|
|
21
21
|
}
|
|
22
|
-
/** Default labeled button with outline variant. */
|
|
22
|
+
/** Default labeled button with outline variant. Plays "click" sound on press. */
|
|
23
23
|
export const Default = {
|
|
24
24
|
args: {
|
|
25
25
|
onClick: noop,
|
package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drawer-action-bar.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"drawer-action-bar.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,YAAoB,EACpB,WAAmB,EACnB,gBAAuB,EACvB,QAAQ,GACT,EAAE,oBAAoB,2CAwDtB"}
|
|
@@ -5,8 +5,17 @@ import { X } from 'lucide-react';
|
|
|
5
5
|
import { Button } from '../../ui/button.js';
|
|
6
6
|
import { RejectFeedbackDialog } from '../../common/reject-feedback-dialog/index.js';
|
|
7
7
|
import { DrawerRevisionInput } from '../../common/drawer-revision-input/index.js';
|
|
8
|
+
import { useSoundAction } from '../../../hooks/use-sound-action.js';
|
|
8
9
|
export function DrawerActionBar({ onReject, onApprove, approveLabel, approveIcon, revisionPlaceholder, rejectDialogTitle, isProcessing = false, isRejecting = false, showRejectButton = true, children, }) {
|
|
9
10
|
const [rejectDialogOpen, setRejectDialogOpen] = useState(false);
|
|
11
|
+
const approveSound = useSoundAction('approve');
|
|
12
|
+
const rejectSound = useSoundAction('reject');
|
|
10
13
|
const disabled = isProcessing || isRejecting;
|
|
11
|
-
return (_jsxs("div", { className: "border-border shrink-0 border-t", children: [children, onReject ? (_jsx(DrawerRevisionInput, { onSubmit: onReject, placeholder: revisionPlaceholder, disabled: disabled || !onReject })) : null, _jsxs("div", { className: "flex items-center gap-2 px-4 pb-4", children: [onReject && showRejectButton ? (_jsxs(_Fragment, { children: [_jsxs(Button, { type: "button", variant: "outline", className: "text-destructive hover:text-destructive", disabled: disabled, onClick: () =>
|
|
14
|
+
return (_jsxs("div", { className: "border-border shrink-0 border-t", children: [children, onReject ? (_jsx(DrawerRevisionInput, { onSubmit: onReject, placeholder: revisionPlaceholder, disabled: disabled || !onReject })) : null, _jsxs("div", { className: "flex items-center gap-2 px-4 pb-4", children: [onReject && showRejectButton ? (_jsxs(_Fragment, { children: [_jsxs(Button, { type: "button", variant: "outline", className: "text-destructive hover:text-destructive", disabled: disabled, onClick: () => {
|
|
15
|
+
rejectSound.play();
|
|
16
|
+
setRejectDialogOpen(true);
|
|
17
|
+
}, children: [_jsx(X, { className: "mr-1.5 h-4 w-4" }), "Reject"] }), _jsx(RejectFeedbackDialog, { open: rejectDialogOpen, onOpenChange: setRejectDialogOpen, onConfirm: onReject, isSubmitting: isRejecting, title: rejectDialogTitle })] })) : null, _jsxs(Button, { type: "button", className: "flex-1", disabled: disabled, onClick: () => {
|
|
18
|
+
approveSound.play();
|
|
19
|
+
onApprove();
|
|
20
|
+
}, children: [approveIcon, approveLabel] })] })] }));
|
|
12
21
|
}
|
package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.stories.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { DrawerActionBar } from './drawer-action-bar.js';
|
|
3
|
+
declare const meta: Meta<typeof DrawerActionBar>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof DrawerActionBar>;
|
|
6
|
+
/** Default — approve button only. Plays "approve" sound on click. */
|
|
7
|
+
export declare const Default: Story;
|
|
8
|
+
/** With approve icon. */
|
|
9
|
+
export declare const WithIcon: Story;
|
|
10
|
+
/** With reject button. Plays "reject" sound on reject click, "approve" on approve. */
|
|
11
|
+
export declare const WithReject: Story;
|
|
12
|
+
/** Processing state — buttons disabled, no sounds play. */
|
|
13
|
+
export declare const Processing: Story;
|
|
14
|
+
/** Rejecting state — buttons disabled. */
|
|
15
|
+
export declare const Rejecting: Story;
|
|
16
|
+
/** With revision input and reject button. */
|
|
17
|
+
export declare const WithRevisionInput: Story;
|
|
18
|
+
/** Custom reject dialog title. */
|
|
19
|
+
export declare const CustomRejectTitle: Story;
|
|
20
|
+
//# sourceMappingURL=drawer-action-bar.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drawer-action-bar.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,eAAe,CAkBtC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9C,qEAAqE;AACrE,eAAO,MAAM,OAAO,EAAE,KAAU,CAAC;AAEjC,yBAAyB;AACzB,eAAO,MAAM,QAAQ,EAAE,KAKtB,CAAC;AAEF,sFAAsF;AACtF,eAAO,MAAM,UAAU,EAAE,KAKxB,CAAC;AAEF,2DAA2D;AAC3D,eAAO,MAAM,UAAU,EAAE,KAMxB,CAAC;AAEF,0CAA0C;AAC1C,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAEF,6CAA6C;AAC7C,eAAO,MAAM,iBAAiB,EAAE,KAM/B,CAAC;AAEF,kCAAkC;AAClC,eAAO,MAAM,iBAAiB,EAAE,KAM/B,CAAC"}
|
package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.stories.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { fn } from '@storybook/test';
|
|
3
|
+
import { Check } from 'lucide-react';
|
|
4
|
+
import { DrawerActionBar } from './drawer-action-bar.js';
|
|
5
|
+
const meta = {
|
|
6
|
+
title: 'Composed/DrawerActionBar',
|
|
7
|
+
component: DrawerActionBar,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'centered',
|
|
11
|
+
},
|
|
12
|
+
args: {
|
|
13
|
+
onApprove: fn().mockName('onApprove'),
|
|
14
|
+
approveLabel: 'Approve',
|
|
15
|
+
},
|
|
16
|
+
decorators: [
|
|
17
|
+
(Story) => (_jsx("div", { className: "w-[400px] rounded-md border", children: _jsx(Story, {}) })),
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
export default meta;
|
|
21
|
+
/** Default — approve button only. Plays "approve" sound on click. */
|
|
22
|
+
export const Default = {};
|
|
23
|
+
/** With approve icon. */
|
|
24
|
+
export const WithIcon = {
|
|
25
|
+
args: {
|
|
26
|
+
approveLabel: 'Approve PRD',
|
|
27
|
+
approveIcon: _jsx(Check, { className: "mr-1.5 h-4 w-4" }),
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
/** With reject button. Plays "reject" sound on reject click, "approve" on approve. */
|
|
31
|
+
export const WithReject = {
|
|
32
|
+
args: {
|
|
33
|
+
onReject: fn().mockName('onReject'),
|
|
34
|
+
approveLabel: 'Approve',
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
/** Processing state — buttons disabled, no sounds play. */
|
|
38
|
+
export const Processing = {
|
|
39
|
+
args: {
|
|
40
|
+
onReject: fn().mockName('onReject'),
|
|
41
|
+
approveLabel: 'Approve',
|
|
42
|
+
isProcessing: true,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
/** Rejecting state — buttons disabled. */
|
|
46
|
+
export const Rejecting = {
|
|
47
|
+
args: {
|
|
48
|
+
onReject: fn().mockName('onReject'),
|
|
49
|
+
approveLabel: 'Approve',
|
|
50
|
+
isRejecting: true,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
/** With revision input and reject button. */
|
|
54
|
+
export const WithRevisionInput = {
|
|
55
|
+
args: {
|
|
56
|
+
onReject: fn().mockName('onReject'),
|
|
57
|
+
approveLabel: 'Approve',
|
|
58
|
+
revisionPlaceholder: 'Ask AI to revise the plan...',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
/** Custom reject dialog title. */
|
|
62
|
+
export const CustomRejectTitle = {
|
|
63
|
+
args: {
|
|
64
|
+
onReject: fn().mockName('onReject'),
|
|
65
|
+
approveLabel: 'Approve Plan',
|
|
66
|
+
rejectDialogTitle: 'Reject Plan',
|
|
67
|
+
},
|
|
68
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-create-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"feature-create-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAC;AAC/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAG5E,YAAY,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAC;AAE/F,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE;QACb,QAAQ,EAAE,OAAO,CAAC;QAClB,SAAS,EAAE,OAAO,CAAC;QACnB,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAcD,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,kGAAkG;IAClG,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,cAAc,EACd,YAAoB,EACpB,gBAAgB,EAChB,QAAQ,EACR,eAAe,GAChB,EAAE,wBAAwB,2CA4S1B"}
|
package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js
CHANGED
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
4
4
|
import { XIcon, PlusIcon, FileIcon, FileTextIcon, ImageIcon, CodeIcon, Trash2Icon, ChevronsUpDown, CheckIcon, } from 'lucide-react';
|
|
5
5
|
import { cn } from '../../../lib/utils.js';
|
|
6
|
+
import { useSoundAction } from '../../../hooks/use-sound-action.js';
|
|
6
7
|
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, DrawerFooter, } from '../../ui/drawer.js';
|
|
7
8
|
import { Button } from '../../ui/button.js';
|
|
8
9
|
import { Input } from '../../ui/input.js';
|
|
@@ -25,6 +26,9 @@ const EMPTY_GATES = {
|
|
|
25
26
|
allowMerge: false,
|
|
26
27
|
};
|
|
27
28
|
export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, isSubmitting = false, workflowDefaults, features, initialParentId, }) {
|
|
29
|
+
const drawerOpenSound = useSoundAction('drawer-open');
|
|
30
|
+
const drawerCloseSound = useSoundAction('drawer-close');
|
|
31
|
+
const createSound = useSoundAction('create');
|
|
28
32
|
const defaultGates = workflowDefaults?.approvalGates ?? EMPTY_GATES;
|
|
29
33
|
const defaultPush = workflowDefaults?.push ?? false;
|
|
30
34
|
const defaultOpenPr = workflowDefaults?.openPr ?? false;
|
|
@@ -35,6 +39,12 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
|
|
|
35
39
|
const [push, setPush] = useState(defaultPush);
|
|
36
40
|
const [openPr, setOpenPr] = useState(defaultOpenPr);
|
|
37
41
|
const [parentId, setParentId] = useState(undefined);
|
|
42
|
+
// Play drawer-open sound when the drawer opens
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (open) {
|
|
45
|
+
drawerOpenSound.play();
|
|
46
|
+
}
|
|
47
|
+
}, [open, drawerOpenSound]);
|
|
38
48
|
// Sync state when workflowDefaults load asynchronously
|
|
39
49
|
useEffect(() => {
|
|
40
50
|
if (workflowDefaults) {
|
|
@@ -60,14 +70,16 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
|
|
|
60
70
|
}, [defaultGates, defaultPush, defaultOpenPr]);
|
|
61
71
|
const handleOpenChange = useCallback((nextOpen) => {
|
|
62
72
|
if (!nextOpen) {
|
|
73
|
+
drawerCloseSound.play();
|
|
63
74
|
resetForm();
|
|
64
75
|
onClose();
|
|
65
76
|
}
|
|
66
|
-
}, [onClose, resetForm]);
|
|
77
|
+
}, [onClose, resetForm, drawerCloseSound]);
|
|
67
78
|
const handleSubmit = useCallback((e) => {
|
|
68
79
|
e.preventDefault();
|
|
69
80
|
if (!name.trim())
|
|
70
81
|
return;
|
|
82
|
+
createSound.play();
|
|
71
83
|
const trimmedDescription = description.trim() || undefined;
|
|
72
84
|
onSubmit({
|
|
73
85
|
name: name.trim(),
|
|
@@ -83,6 +95,7 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
|
|
|
83
95
|
openPr,
|
|
84
96
|
...(parentId ? { parentId } : {}),
|
|
85
97
|
});
|
|
98
|
+
resetForm();
|
|
86
99
|
}, [
|
|
87
100
|
name,
|
|
88
101
|
description,
|
|
@@ -93,6 +106,8 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
|
|
|
93
106
|
push,
|
|
94
107
|
openPr,
|
|
95
108
|
parentId,
|
|
109
|
+
createSound,
|
|
110
|
+
resetForm,
|
|
96
111
|
]);
|
|
97
112
|
const handleAddFiles = useCallback(async () => {
|
|
98
113
|
try {
|
|
@@ -109,7 +124,13 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
|
|
|
109
124
|
setAttachments((prev) => prev.filter((f) => f.path !== path));
|
|
110
125
|
}, []);
|
|
111
126
|
const hasFeatures = features && features.length > 0;
|
|
112
|
-
return (_jsx(Drawer, { direction: "right", modal: false, handleOnly: true, open: open, onOpenChange: handleOpenChange, children: _jsxs(DrawerContent, { direction: "right", className: "w-96", showCloseButton: false, children: [_jsx("button", { type: "button", "aria-label": "Close", onClick:
|
|
127
|
+
return (_jsx(Drawer, { direction: "right", modal: false, handleOnly: true, open: open, onOpenChange: handleOpenChange, children: _jsxs(DrawerContent, { direction: "right", className: "w-96", showCloseButton: false, children: [_jsx("button", { type: "button", "aria-label": "Close", onClick: () => {
|
|
128
|
+
drawerCloseSound.play();
|
|
129
|
+
onClose();
|
|
130
|
+
}, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", children: _jsx(XIcon, { className: "size-4" }) }), _jsxs(DrawerHeader, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-2.5 w-2.5 shrink-0 rounded-full bg-blue-500" }), _jsx(DrawerTitle, { children: "NEW FEATURE" })] }), _jsx(DrawerDescription, { asChild: true, children: _jsx("div", { children: _jsx(Badge, { variant: "secondary", children: "Creating..." }) }) })] }), _jsx(Separator, {}), _jsx("div", { className: "flex-1 overflow-y-auto p-4", children: _jsxs("form", { id: "create-feature-form", onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "feature-name", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "FEATURE NAME" }), _jsx(Input, { id: "feature-name", placeholder: "e.g. GitHub OAuth Login", value: name, onChange: (e) => setName(e.target.value), required: true, disabled: isSubmitting })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "feature-description", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "DESCRIPTION" }), _jsx(Textarea, { id: "feature-description", placeholder: "Describe what this feature does...", value: description, onChange: (e) => setDescription(e.target.value), rows: 4, disabled: isSubmitting })] }), hasFeatures ? (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "parent-feature", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "PARENT FEATURE" }), _jsx(ParentFeatureCombobox, { features: features, value: parentId, onChange: setParentId, disabled: isSubmitting })] })) : null, _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "APPROVE" }), _jsx(CheckboxGroup, { label: "Autonomous Mode", description: "YOLO!", parentAriaLabel: "Auto approve all", options: AUTO_APPROVE_OPTIONS, value: approvalGates, onValueChange: setApprovalGates, disabled: isSubmitting })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "GIT" }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(CheckboxGroupItem, { id: "push", label: "Push", description: "Push branch to remote after implementation.", checked: push || openPr, onCheckedChange: setPush, disabled: openPr || isSubmitting }), _jsx(CheckboxGroupItem, { id: "open-pr", label: "Create PR", description: "Open a pull request after pushing.", checked: openPr, onCheckedChange: setOpenPr, disabled: isSubmitting })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: ["ATTACHMENTS", attachments.length > 0 && (_jsxs("span", { className: "text-muted-foreground/60 ml-1.5", children: ["(", attachments.length, ")"] }))] }), _jsxs(Button, { type: "button", variant: "outline", size: "xs", onClick: handleAddFiles, disabled: isSubmitting, children: [_jsx(PlusIcon, { className: "size-3" }), "Add Files"] })] }), attachments.length > 0 && (_jsx("div", { className: "flex flex-col gap-2", children: attachments.map((file) => (_jsx(AttachmentCard, { file: file, onRemove: () => handleRemoveFile(file.path), disabled: isSubmitting }, file.path))) }))] })] }) }), _jsx(Separator, {}), _jsxs(DrawerFooter, { className: "flex-row justify-end gap-2", children: [_jsx(Button, { variant: "outline", onClick: () => {
|
|
131
|
+
drawerCloseSound.play();
|
|
132
|
+
onClose();
|
|
133
|
+
}, disabled: isSubmitting, children: "Cancel" }), _jsx(Button, { type: "submit", form: "create-feature-form", disabled: !name.trim() || isSubmitting, children: isSubmitting ? 'Creating...' : '+ Create Feature' })] })] }) }));
|
|
113
134
|
}
|
|
114
135
|
function ParentFeatureCombobox({ features, value, onChange, disabled, }) {
|
|
115
136
|
const [open, setOpen] = useState(false);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"feature-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAGxE,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,aAAa,CAAC,EAC5B,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,UAAkB,GACnB,EAAE,kBAAkB,2CA8IpB"}
|
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { XIcon, Loader2, Trash2, ExternalLink, GitCommitHorizontal } from 'lucide-react';
|
|
4
4
|
import { PrStatus } from '../../../../../../packages/core/src/domain/generated/output.js';
|
|
5
5
|
import { cn } from '../../../lib/utils.js';
|
|
6
|
+
import { useSoundAction } from '../../../hooks/use-sound-action.js';
|
|
6
7
|
import { OpenActionMenu } from '../../common/open-action-menu/index.js';
|
|
7
8
|
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, } from '../../ui/drawer.js';
|
|
8
9
|
import { Button } from '../../ui/button.js';
|
|
@@ -14,10 +15,20 @@ import { CiStatusBadge } from '../../common/ci-status-badge/index.js';
|
|
|
14
15
|
import { featureNodeStateConfig, lifecycleDisplayLabels } from '../../common/feature-node/index.js';
|
|
15
16
|
import { useFeatureActions } from './use-feature-actions.js';
|
|
16
17
|
export function FeatureDrawer({ selectedNode, onClose, onDelete, isDeleting = false, }) {
|
|
18
|
+
const drawerOpenSound = useSoundAction('drawer-open');
|
|
19
|
+
const drawerCloseSound = useSoundAction('drawer-close');
|
|
17
20
|
return (_jsx(Drawer, { direction: "right", modal: false, handleOnly: true, open: selectedNode !== null, onOpenChange: (open) => {
|
|
18
|
-
if (
|
|
21
|
+
if (open) {
|
|
22
|
+
drawerOpenSound.play();
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
drawerCloseSound.play();
|
|
19
26
|
onClose();
|
|
20
|
-
|
|
27
|
+
}
|
|
28
|
+
}, children: _jsx(DrawerContent, { direction: "right", className: "w-96", showCloseButton: false, children: selectedNode ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "aria-label": "Close", onClick: () => {
|
|
29
|
+
drawerCloseSound.play();
|
|
30
|
+
onClose();
|
|
31
|
+
}, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", children: _jsx(XIcon, { className: "size-4" }) }), _jsxs(DrawerHeader, { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: selectedNode.name }), _jsx(DrawerDescription, { children: selectedNode.featureId })] }), selectedNode.repositoryPath && selectedNode.branch ? (_jsx(DrawerActions, { repositoryPath: selectedNode.repositoryPath, branch: selectedNode.branch, specPath: selectedNode.specPath })) : null, _jsx(Separator, {}), _jsxs("div", { "data-testid": "feature-drawer-status", className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: lifecycleDisplayLabels[selectedNode.lifecycle] }), _jsx(StateBadge, { data: selectedNode }), selectedNode.progress > 0 ? (_jsxs("div", { "data-testid": "feature-drawer-progress", className: "flex flex-col gap-1", children: [_jsxs("div", { className: "text-muted-foreground flex items-center justify-between text-xs", children: [_jsx("span", { children: "Progress" }), _jsxs("span", { children: [selectedNode.progress, "%"] })] }), _jsx("div", { className: "bg-muted h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: cn('h-full rounded-full transition-all', featureNodeStateConfig[selectedNode.state].progressClass), style: { width: `${selectedNode.progress}%` } }) })] })) : null] }), selectedNode.pr ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx(PrInfoSection, { pr: selectedNode.pr })] })) : null, _jsx(Separator, {}), _jsx(DetailsSection, { data: selectedNode }), onDelete ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx("div", { "data-testid": "feature-drawer-delete", className: "p-4", children: _jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "destructive", className: "w-full", disabled: isDeleting, children: [_jsx(Trash2, { className: "mr-2 h-4 w-4" }), "Delete feature"] }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete feature?" }), _jsxs(AlertDialogDescription, { children: ["This will permanently delete ", _jsx("strong", { children: selectedNode.name }), " (", selectedNode.featureId, "). This action cannot be undone.", selectedNode.state === 'running' ? (_jsx(_Fragment, { children: " This feature has a running agent that will be stopped." })) : null] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: isDeleting, children: "Cancel" }), _jsx(AlertDialogAction, { variant: "destructive", disabled: isDeleting, onClick: () => onDelete(selectedNode.featureId), children: isDeleting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Deleting\u2026"] })) : ('Delete') })] })] })] }) })] })) : null] })) : null }) }));
|
|
21
32
|
}
|
|
22
33
|
function StateBadge({ data }) {
|
|
23
34
|
const config = featureNodeStateConfig[data.state];
|
package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prd-questionnaire.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prd-questionnaire.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAoB,EACpB,WAAmB,EACnB,UAAkB,GACnB,EAAE,qBAAqB,kDAiLvB"}
|
|
@@ -6,28 +6,41 @@ import { cn } from '../../../lib/utils.js';
|
|
|
6
6
|
import { Button } from '../../ui/button.js';
|
|
7
7
|
import { Badge } from '../../ui/badge.js';
|
|
8
8
|
import { DrawerActionBar } from '../../common/drawer-action-bar/index.js';
|
|
9
|
+
import { useSoundAction } from '../../../hooks/use-sound-action.js';
|
|
9
10
|
export function PrdQuestionnaire({ data, selections, onSelect, onApprove, onReject, isProcessing = false, isRejecting = false, showHeader = false, }) {
|
|
10
11
|
const { question, context, questions, finalAction } = data;
|
|
11
12
|
const [currentStep, setCurrentStep] = useState(0);
|
|
13
|
+
const selectSound = useSoundAction('select');
|
|
14
|
+
const navigateSound = useSoundAction('navigate');
|
|
12
15
|
const total = questions.length;
|
|
13
16
|
const isFirstStep = currentStep === 0;
|
|
14
17
|
const isLastStep = currentStep === total - 1;
|
|
15
18
|
const currentQuestion = questions[currentStep];
|
|
16
19
|
const answeredCount = useMemo(() => Object.keys(selections).length, [selections]);
|
|
17
20
|
const handleSelect = useCallback((questionId, optionId) => {
|
|
21
|
+
selectSound.play();
|
|
18
22
|
onSelect(questionId, optionId);
|
|
19
23
|
// Auto-advance to the next step after selection (unless last step)
|
|
20
24
|
if (!isLastStep) {
|
|
21
25
|
setTimeout(() => setCurrentStep((s) => s + 1), 250);
|
|
22
26
|
}
|
|
23
|
-
}, [onSelect, isLastStep]);
|
|
27
|
+
}, [onSelect, isLastStep, selectSound]);
|
|
24
28
|
if (total === 0)
|
|
25
29
|
return null;
|
|
26
|
-
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto p-4", children: [showHeader ? (_jsxs("div", { className: "border-border flex items-start gap-3 border-b pb-3", children: [_jsx("div", { className: "mt-1.5 h-2 w-2 shrink-0 rounded-full bg-amber-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-foreground mb-1.5 text-sm font-bold", children: question }), _jsx("p", { className: "text-muted-foreground text-xs leading-relaxed", children: context })] })] })) : null, _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("label", { className: "text-foreground min-w-0 flex-1 text-sm font-semibold", children: currentQuestion.question }), _jsx("div", { className: "mt-1.5 flex shrink-0 gap-1", children: questions.map((q, idx) => (_jsx("button", { type: "button", "aria-label": `Go to question ${idx + 1}`, className: cn('h-1.5 rounded-full transition-all duration-200', idx === currentStep ? 'bg-primary w-4' : 'w-1.5', idx !== currentStep && selections[q.id] ? 'bg-primary/50' : '', idx !== currentStep && !selections[q.id] ? 'bg-muted-foreground/25' : ''), onClick: () =>
|
|
30
|
+
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto p-4", children: [showHeader ? (_jsxs("div", { className: "border-border flex items-start gap-3 border-b pb-3", children: [_jsx("div", { className: "mt-1.5 h-2 w-2 shrink-0 rounded-full bg-amber-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-foreground mb-1.5 text-sm font-bold", children: question }), _jsx("p", { className: "text-muted-foreground text-xs leading-relaxed", children: context })] })] })) : null, _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("label", { className: "text-foreground min-w-0 flex-1 text-sm font-semibold", children: currentQuestion.question }), _jsx("div", { className: "mt-1.5 flex shrink-0 gap-1", children: questions.map((q, idx) => (_jsx("button", { type: "button", "aria-label": `Go to question ${idx + 1}`, className: cn('h-1.5 rounded-full transition-all duration-200', idx === currentStep ? 'bg-primary w-4' : 'w-1.5', idx !== currentStep && selections[q.id] ? 'bg-primary/50' : '', idx !== currentStep && !selections[q.id] ? 'bg-muted-foreground/25' : ''), onClick: () => {
|
|
31
|
+
navigateSound.play();
|
|
32
|
+
setCurrentStep(idx);
|
|
33
|
+
} }, q.id))) })] }), _jsx("div", { className: "space-y-2", children: currentQuestion.options.map((opt, optIdx) => {
|
|
27
34
|
const selected = selections[currentQuestion.id] === opt.id;
|
|
28
35
|
const letter = String.fromCharCode(65 + optIdx);
|
|
29
36
|
return (_jsx("button", { type: "button", className: cn('border-border w-full rounded-md border px-3 py-3 text-left text-xs transition-all', 'hover:border-primary/70 hover:bg-primary/5 group', selected && 'border-primary bg-primary/5', opt.isNew && 'animate-option-highlight'), disabled: isProcessing, onClick: () => handleSelect(currentQuestion.id, opt.id), children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsxs("span", { className: "text-muted-foreground mt-0.5 font-mono text-xs", children: [letter, "."] }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "mb-0.5 flex items-center gap-2", children: [_jsx("span", { className: "text-foreground text-xs font-semibold", children: opt.label }), opt.recommended ? (_jsx(Badge, { className: "px-1.5 py-0 text-[10px]", children: "AI Recommended" })) : null, opt.isNew ? (_jsx(Badge, { className: "border-transparent bg-emerald-600 px-1.5 py-0 text-[10px] text-white hover:bg-emerald-600/80", children: "New" })) : null] }), _jsx("div", { className: "text-muted-foreground text-xs leading-snug", children: opt.rationale })] })] }) }, opt.id));
|
|
30
|
-
}) })] }), _jsxs("div", { className: "flex items-center justify-between pt-2", children: [_jsxs(Button, { type: "button", variant: "ghost", size: "sm", disabled: isFirstStep || isProcessing, onClick: () =>
|
|
37
|
+
}) })] }), _jsxs("div", { className: "flex items-center justify-between pt-2", children: [_jsxs(Button, { type: "button", variant: "ghost", size: "sm", disabled: isFirstStep || isProcessing, onClick: () => {
|
|
38
|
+
navigateSound.play();
|
|
39
|
+
setCurrentStep((s) => s - 1);
|
|
40
|
+
}, children: [_jsx(ChevronLeft, { className: "mr-1 h-4 w-4" }), "Previous"] }), !isLastStep ? (_jsxs(Button, { type: "button", variant: "ghost", size: "sm", disabled: isProcessing, onClick: () => {
|
|
41
|
+
navigateSound.play();
|
|
42
|
+
setCurrentStep((s) => s + 1);
|
|
43
|
+
}, children: [selections[currentQuestion.id] ? 'Next' : 'Skip', _jsx(ChevronRight, { className: "ml-1 h-4 w-4" })] })) : null] })] }), _jsx(DrawerActionBar, { onReject: onReject, onApprove: () => onApprove(finalAction.id), approveLabel: finalAction.label, approveIcon: _jsx(Check, { className: "mr-1.5 h-4 w-4" }), revisionPlaceholder: "Ask AI to refine requirements...", isProcessing: isProcessing, isRejecting: isRejecting, children: _jsx("div", { className: cn('bg-muted h-1.5 overflow-hidden', (answeredCount > 0 && answeredCount < total) || isProcessing
|
|
31
44
|
? 'opacity-100'
|
|
32
45
|
: 'opacity-0', 'transition-opacity duration-200'), "data-testid": "progress-bar-container", children: isProcessing ? (_jsx("div", { className: "bg-primary animate-indeterminate-progress h-full w-1/3" })) : (_jsx("div", { className: "bg-primary h-full transition-all duration-300", style: { width: `${total > 0 ? (answeredCount / total) * 100 : 0}%` }, "data-testid": "progress-bar" })) }) })] }));
|
|
33
46
|
}
|
package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { PrdQuestionnaireDrawer } from './prd-questionnaire-drawer.js';
|
|
|
4
4
|
declare const meta: Meta<typeof PrdQuestionnaire>;
|
|
5
5
|
export default meta;
|
|
6
6
|
type Story = StoryObj<typeof PrdQuestionnaire>;
|
|
7
|
-
/** Default state — first step shown, no selections. Click options to auto-advance. */
|
|
7
|
+
/** Default state — first step shown, no selections. Click options to auto-advance. Plays "select" on option click, "navigate" on step/nav buttons. */
|
|
8
8
|
export declare const Default: Story;
|
|
9
9
|
/** Starting with partial selections — step dots reflect answered state. */
|
|
10
10
|
export declare const WithSelections: Story;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prd-questionnaire.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAiKpE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,gBAAgB,CAkBvC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAU/C,
|
|
1
|
+
{"version":3,"file":"prd-questionnaire.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAiKpE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,gBAAgB,CAkBvC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAU/C,sJAAsJ;AACtJ,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,cAAc,EAAE,KAW5B,CAAC;AAEF,uEAAuE;AACvE,eAAO,MAAM,WAAW,EAAE,KAczB,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,QAAQ,EAAE,KAStB,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,WAAW,EAAE,KA8BzB,CAAC;AAIF,KAAK,WAAW,GAAG,QAAQ,CAAC,OAAO,sBAAsB,CAAC,CAAC;AA0C3D,8DAA8D;AAC9D,eAAO,MAAM,QAAQ,EAAE,WAWtB,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,WAepC,CAAC;AAEF,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,EAAE,WAW9B,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,WAY3B,CAAC;AAaF,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,EAAE,KAQ9B,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,cAAc,EAAE,KAO5B,CAAC"}
|
package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.js
CHANGED
|
@@ -165,7 +165,7 @@ const mockData = {
|
|
|
165
165
|
questions: mockQuestions,
|
|
166
166
|
finalAction: mockFinalAction,
|
|
167
167
|
};
|
|
168
|
-
/** Default state — first step shown, no selections. Click options to auto-advance. */
|
|
168
|
+
/** Default state — first step shown, no selections. Click options to auto-advance. Plays "select" on option click, "navigate" on step/nav buttons. */
|
|
169
169
|
export const Default = {
|
|
170
170
|
render: () => _jsx(InteractiveQuestionnaire, { data: mockData }),
|
|
171
171
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar-collapse-toggle.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/sidebar-collapse-toggle/sidebar-collapse-toggle.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sidebar-collapse-toggle.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/sidebar-collapse-toggle/sidebar-collapse-toggle.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,qBAAqB,CAAC,EAAE,SAAS,EAAE,EAAE,0BAA0B,2CA8B9E"}
|
|
@@ -4,8 +4,21 @@ import { PanelLeft } from 'lucide-react';
|
|
|
4
4
|
import { useSidebar } from '../../ui/sidebar.js';
|
|
5
5
|
import { Button } from '../../ui/button.js';
|
|
6
6
|
import { cn } from '../../../lib/utils.js';
|
|
7
|
+
import { useSoundAction } from '../../../hooks/use-sound-action.js';
|
|
7
8
|
export function SidebarCollapseToggle({ className }) {
|
|
8
9
|
const { toggleSidebar, open } = useSidebar();
|
|
10
|
+
const expandSound = useSoundAction('expand');
|
|
11
|
+
const collapseSound = useSoundAction('collapse');
|
|
9
12
|
const label = open ? 'Collapse sidebar' : 'Expand sidebar';
|
|
10
|
-
|
|
13
|
+
const handleClick = () => {
|
|
14
|
+
// Play sound based on current state (before toggle)
|
|
15
|
+
if (open) {
|
|
16
|
+
collapseSound.play();
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
expandSound.play();
|
|
20
|
+
}
|
|
21
|
+
toggleSidebar();
|
|
22
|
+
};
|
|
23
|
+
return (_jsx("div", { className: cn('flex', className), children: _jsx(Button, { "data-testid": "sidebar-collapse-toggle", variant: "ghost", size: "icon", className: "size-7 cursor-pointer group-data-[collapsible=icon]:size-8!", onClick: handleClick, "aria-label": label, children: _jsx(PanelLeft, { className: "size-4" }) }) }));
|
|
11
24
|
}
|
|
@@ -3,6 +3,8 @@ import { SidebarCollapseToggle } from './sidebar-collapse-toggle.js';
|
|
|
3
3
|
declare const meta: Meta<typeof SidebarCollapseToggle>;
|
|
4
4
|
export default meta;
|
|
5
5
|
type Story = StoryObj<typeof meta>;
|
|
6
|
+
/** Expanded state — clicking plays "collapse" sound. */
|
|
6
7
|
export declare const Expanded: Story;
|
|
8
|
+
/** Collapsed state — clicking plays "expand" sound. */
|
|
7
9
|
export declare const Collapsed: Story;
|
|
8
10
|
//# sourceMappingURL=sidebar-collapse-toggle.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar-collapse-toggle.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/sidebar-collapse-toggle/sidebar-collapse-toggle.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,qBAAqB,CAkB5C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,QAAQ,EAAE,KAAU,CAAC;AAElC,eAAO,MAAM,SAAS,EAAE,KAYvB,CAAC"}
|
|
1
|
+
{"version":3,"file":"sidebar-collapse-toggle.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/sidebar-collapse-toggle/sidebar-collapse-toggle.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,qBAAqB,CAkB5C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,wDAAwD;AACxD,eAAO,MAAM,QAAQ,EAAE,KAAU,CAAC;AAElC,uDAAuD;AACvD,eAAO,MAAM,SAAS,EAAE,KAYvB,CAAC"}
|
|
@@ -13,7 +13,9 @@ const meta = {
|
|
|
13
13
|
],
|
|
14
14
|
};
|
|
15
15
|
export default meta;
|
|
16
|
+
/** Expanded state — clicking plays "collapse" sound. */
|
|
16
17
|
export const Expanded = {};
|
|
18
|
+
/** Collapsed state — clicking plays "expand" sound. */
|
|
17
19
|
export const Collapsed = {
|
|
18
20
|
decorators: [
|
|
19
21
|
(Story) => (_jsx(SidebarProvider, { defaultOpen: false, children: _jsx(SidebarMenu, { children: _jsx(SidebarMenuItem, { children: _jsx(Story, {}) }) }) })),
|
package/dist/src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar-nav-item.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sidebar-nav-item.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAI/C,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAc,EAAE,EAAE,mBAAmB,2CAa9F"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import Link from 'next/link';
|
|
3
4
|
import { SidebarMenuItem, SidebarMenuButton } from '../../ui/sidebar.js';
|
|
5
|
+
import { useSoundAction } from '../../../hooks/use-sound-action.js';
|
|
4
6
|
export function SidebarNavItem({ icon: Icon, label, href, active = false }) {
|
|
5
|
-
|
|
7
|
+
const navigateSound = useSoundAction('navigate');
|
|
8
|
+
return (_jsx(SidebarMenuItem, { "data-testid": "sidebar-nav-item", children: _jsx(SidebarMenuButton, { asChild: true, isActive: active, tooltip: label, children: _jsxs(Link, { href: href, onClick: () => navigateSound.play(), children: [_jsx(Icon, {}), _jsx("span", { children: label })] }) }) }));
|
|
6
9
|
}
|
package/dist/src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.stories.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { SidebarNavItem } from './sidebar-nav-item.js';
|
|
|
3
3
|
declare const meta: Meta<typeof SidebarNavItem>;
|
|
4
4
|
export default meta;
|
|
5
5
|
type Story = StoryObj<typeof meta>;
|
|
6
|
+
/** Default — clicking plays "navigate" sound. */
|
|
6
7
|
export declare const Default: Story;
|
|
7
8
|
export declare const Active: Story;
|
|
8
9
|
export declare const WithBrainIcon: Story;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar-nav-item.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,cAAc,CAgBrC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,KAOpB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAM3B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAM9B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAO/B,CAAC"}
|
|
1
|
+
{"version":3,"file":"sidebar-nav-item.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/sidebar-nav-item/sidebar-nav-item.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,cAAc,CAgBrC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,iDAAiD;AACjD,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,KAOpB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAM3B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAM9B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAO/B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tech-decisions-review.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tech-decisions-review.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,wBAAwB,EAAgB,MAAM,gCAAgC,CAAC;AAgH7F,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,YAAoB,EACpB,WAAmB,GACpB,EAAE,wBAAwB,kDA6C1B"}
|
package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.js
CHANGED
|
@@ -5,6 +5,7 @@ import Markdown from 'react-markdown';
|
|
|
5
5
|
import { Check, ChevronRight, GitCompareArrows, Layers } from 'lucide-react';
|
|
6
6
|
import { Badge } from '../../ui/badge.js';
|
|
7
7
|
import { DrawerActionBar } from '../../common/drawer-action-bar/index.js';
|
|
8
|
+
import { useSoundAction } from '../../../hooks/use-sound-action.js';
|
|
8
9
|
const markdownComponents = {
|
|
9
10
|
p: ({ children }) => (_jsx("p", { className: "text-muted-foreground mb-2 text-xs leading-relaxed last:mb-0", children: children })),
|
|
10
11
|
strong: ({ children }) => _jsx("strong", { className: "text-foreground font-semibold", children: children }),
|
|
@@ -18,8 +19,20 @@ const markdownComponents = {
|
|
|
18
19
|
};
|
|
19
20
|
function DecisionCard({ decision, index }) {
|
|
20
21
|
const [alternativesOpen, setAlternativesOpen] = useState(false);
|
|
22
|
+
const expandSound = useSoundAction('expand');
|
|
23
|
+
const collapseSound = useSoundAction('collapse');
|
|
24
|
+
const handleToggleAlternatives = () => {
|
|
25
|
+
// Play sound based on current state (before toggle)
|
|
26
|
+
if (alternativesOpen) {
|
|
27
|
+
collapseSound.play();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
expandSound.play();
|
|
31
|
+
}
|
|
32
|
+
setAlternativesOpen((prev) => !prev);
|
|
33
|
+
};
|
|
21
34
|
return (_jsxs("div", { className: "border-border rounded-lg border", children: [_jsxs("div", { className: "space-y-3 px-4 py-3", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("span", { className: "bg-primary text-primary-foreground flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-bold", children: index + 1 }), _jsxs("div", { className: "min-w-0", children: [_jsx("h3", { className: "text-foreground text-sm leading-tight font-semibold", children: decision.title }), _jsx("p", { className: "text-muted-foreground mt-0.5 text-xs", children: decision.chosen })] })] }), 'decisionName' in decision &&
|
|
22
|
-
decision.decisionName ? (_jsx(Badge, { variant: "secondary", className: "bg-primary/10 text-primary shrink-0", children: decision.decisionName })) : null] }), decision.rationale ? (_jsx(Markdown, { components: markdownComponents, children: decision.rationale })) : null] }), decision.rejected.length > 0 ? (_jsxs("div", { className: "border-border border-t", children: [_jsxs("button", { type: "button", onClick:
|
|
35
|
+
decision.decisionName ? (_jsx(Badge, { variant: "secondary", className: "bg-primary/10 text-primary shrink-0", children: decision.decisionName })) : null] }), decision.rationale ? (_jsx(Markdown, { components: markdownComponents, children: decision.rationale })) : null] }), decision.rejected.length > 0 ? (_jsxs("div", { className: "border-border border-t", children: [_jsxs("button", { type: "button", onClick: handleToggleAlternatives, className: "text-muted-foreground hover:bg-muted/50 flex w-full items-center gap-1.5 px-4 py-3 text-xs font-medium transition-colors", children: [_jsx(ChevronRight, { className: `h-3.5 w-3.5 transition-transform ${alternativesOpen ? 'rotate-90' : ''}` }), _jsx(Layers, { className: "h-3.5 w-3.5" }), "Other Options Considered (", decision.rejected.length, ")"] }), alternativesOpen ? (_jsx("div", { className: "space-y-1.5 px-4 pb-3", children: decision.rejected.map((alt) => (_jsx("div", { className: "bg-primary/5 rounded-md px-3 py-2", children: _jsx("span", { className: "text-foreground text-xs", children: alt }) }, alt))) })) : null] })) : null] }));
|
|
23
36
|
}
|
|
24
37
|
export function TechDecisionsReview({ data, onApprove, onReject, isProcessing = false, isRejecting = false, }) {
|
|
25
38
|
const { summary, decisions } = data;
|
|
@@ -4,7 +4,7 @@ import { TechDecisionsDrawer } from './tech-decisions-drawer.js';
|
|
|
4
4
|
declare const meta: Meta<typeof TechDecisionsReview>;
|
|
5
5
|
export default meta;
|
|
6
6
|
type Story = StoryObj<typeof TechDecisionsReview>;
|
|
7
|
-
/** Default — scrollable list of decisions taken. */
|
|
7
|
+
/** Default — scrollable list of decisions taken. "Other Options Considered" toggle plays expand/collapse sounds. */
|
|
8
8
|
export declare const Default: Story;
|
|
9
9
|
/** Processing state — approve button disabled. */
|
|
10
10
|
export declare const Processing: Story;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tech-decisions-review.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA0C9D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,mBAAmB,CAc1C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAElD,
|
|
1
|
+
{"version":3,"file":"tech-decisions-review.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA0C9D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,mBAAmB,CAc1C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAElD,oHAAoH;AACpH,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,UAAU,EAAE,KAMxB,CAAC;AAEF,uBAAuB;AACvB,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAEF,8BAA8B;AAC9B,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAIF,KAAK,WAAW,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AA8BxD,uCAAuC;AACvC,eAAO,MAAM,QAAQ,EAAE,WAWtB,CAAC;AAEF,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,EAAE,WAY9B,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,WAa3B,CAAC;AAIF,kDAAkD;AAClD,eAAO,MAAM,gBAAgB,EAAE,KAM9B,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,cAAc,EAAE,KAO5B,CAAC"}
|