@conscience-technology/ctds 0.3.4 → 0.4.1

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.
Files changed (53) hide show
  1. package/assets/components/Button/Button.module.css +2 -2
  2. package/assets/components/EventListItem/EventListItem.module.css +220 -0
  3. package/assets/components/EventListItem/EventListItem.tsx +205 -0
  4. package/assets/components/EventListItem/index.ts +8 -0
  5. package/assets/components/Icon/Icon.tsx +80 -41
  6. package/assets/components/Kanban/Kanban.module.css +339 -0
  7. package/assets/components/Kanban/Kanban.tsx +371 -0
  8. package/assets/components/Kanban/index.ts +10 -0
  9. package/assets/components/ListItem/ListItem.module.css +91 -211
  10. package/assets/components/ListItem/ListItem.tsx +130 -154
  11. package/assets/components/ListItem/index.ts +2 -2
  12. package/assets/components/MetricCard/MetricCard.module.css +5 -5
  13. package/assets/components/PageHeader/PageHeader.module.css +109 -0
  14. package/assets/components/PageHeader/PageHeader.tsx +112 -0
  15. package/assets/components/PageHeader/index.ts +2 -0
  16. package/assets/components/Sidebar/Sidebar.module.css +81 -4
  17. package/assets/components/Sidebar/Sidebar.tsx +11 -2
  18. package/assets/components/SplitButton/SplitButton.module.css +3 -3
  19. package/assets/components/Stepper/Stepper.module.css +196 -52
  20. package/assets/components/Stepper/Stepper.tsx +68 -13
  21. package/assets/components/Switch/Switch.module.css +1 -9
  22. package/assets/components/Topbar/Topbar.module.css +33 -5
  23. package/assets/components/Topbar/Topbar.tsx +62 -7
  24. package/assets/components/_data.ts +11 -4
  25. package/assets/components/index.ts +2 -0
  26. package/assets/components/tokens.css +23 -10
  27. package/assets/prompts/ASSEMBLY.md +219 -0
  28. package/assets/prompts/PRINCIPLES.md +70 -0
  29. package/assets/prompts/axes/icon.md +7 -1
  30. package/assets/prompts/axes/palette.md +11 -0
  31. package/assets/prompts/components/_variants.md +5 -1
  32. package/assets/prompts/components/callout.md +3 -3
  33. package/assets/prompts/components/event-list-item.md +103 -0
  34. package/assets/prompts/components/generated-image.md +80 -0
  35. package/assets/prompts/components/hint.md +57 -0
  36. package/assets/prompts/components/kanban.md +167 -0
  37. package/assets/prompts/components/list-item.md +182 -204
  38. package/assets/prompts/components/metric-card.md +2 -2
  39. package/assets/prompts/components/page-header.md +155 -0
  40. package/assets/prompts/components/toast.md +1 -0
  41. package/assets/prompts/components/topbar.md +77 -59
  42. package/assets/prompts/recipes/README.md +102 -0
  43. package/assets/prompts/recipes/card-row.md +58 -0
  44. package/assets/prompts/recipes/form-footer.md +76 -0
  45. package/assets/prompts/recipes/meta-line.md +61 -0
  46. package/assets/prompts/recipes/page-banner.md +121 -0
  47. package/assets/prompts/recipes/page-header.md +93 -0
  48. package/assets/prompts/recipes/section-header.md +90 -0
  49. package/assets/prompts/themes/focus.md +72 -0
  50. package/assets/skills/ctds/SKILL.md +1 -0
  51. package/assets/skills/ctds-page/SKILL.md +12 -2
  52. package/assets/skills/ctds-wireframe/SKILL.md +35 -1
  53. package/package.json +2 -4
@@ -3,12 +3,13 @@
3
3
  /**
4
4
  * 의미 기반 Icon 컴포넌트.
5
5
  *
6
- * 설계 원칙 — "family별 독립 세트":
7
- * - 각 family(phosphor/solar/lucide)는 자기만의 아이콘 세트를 가진다.
8
- * - 서로 다른 라이브러리 간의 "의미 매핑"은 하지 않는다.
9
- * (search 하나를 phosphor·solar·lucide 세 군데에서 억지로 연결하지 않음)
10
- * - 활성 family에 해당 이름이 없으면 그 family 전용 placeholder 아이콘을 렌더.
11
- * (레이아웃 공간 유지 + 축 전환 시 "어떤 아이콘이 그 family엔 없다"는 사실이 시각적으로 드러남)
6
+ * 설계 원칙 — "phosphor 기준 전면 매핑":
7
+ * - phosphor를 기준 세트로 삼고, solar/lucide는 가능한 한 의미가 가장 가까운
8
+ * 아이콘으로 1:1 매핑한다. family 축을 바꿔도 "그림이 비는" 자리가 생기지 않도록.
9
+ * - 라이브러리에 적절한 분리 아이콘이 없으면 "수렴 매핑"을 허용한다
10
+ * (예: solar에 자동차 아이콘이 없음 → truck/car가 같은 Truck으로 수렴).
11
+ * 이건 라이브러리 한계라는 사실을 받아들이는 거지, 설계 결함이 아님.
12
+ * - 매핑 자체가 아예 없는 경우에만 family 전용 placeholder("빗금 사각형")를 렌더.
12
13
  *
13
14
  * weight(regular/fill) 반응:
14
15
  * phosphor → weight prop으로 반응
@@ -390,6 +391,33 @@ import {
390
391
  MedalRibbonStarLinear as SoMedalL, MedalRibbonStarBold as SoMedalB,
391
392
  CrownLinear as SoCrownL, CrownBold as SoCrownB,
392
393
  LeafLinear as SoLeafL, LeafBold as SoLeafB,
394
+ // --- 수렴 분리용 추가 ---
395
+ SmileCircleLinear as SoSmileyHappyL, SmileCircleBold as SoSmileyHappyB,
396
+ ConfoundedCircleLinear as SoSmileyMehL, ConfoundedCircleBold as SoSmileyMehB,
397
+ SadCircleLinear as SoSmileySadL, SadCircleBold as SoSmileySadB,
398
+ LockUnlockedLinear as SoLockOpenL, LockUnlockedBold as SoLockOpenB,
399
+ GarageLinear as SoFactoryL, GarageBold as SoFactoryB,
400
+ CompassBigLinear as SoNavigationL, CompassBigBold as SoNavigationB,
401
+ MinimizeSquareLinear as SoCornersInL, MinimizeSquareBold as SoCornersInB,
402
+ MaximizeSquareLinear as SoCornersOutL, MaximizeSquareBold as SoCornersOutB,
403
+ RefreshCircleLinear as SoArrowsClockwiseL, RefreshCircleBold as SoArrowsClockwiseB,
404
+ LinkMinimalisticLinear as SoLinkSimpleL, LinkMinimalisticBold as SoLinkSimpleB,
405
+ RoundAltArrowDownLinear as SoCaretCircleDownL, RoundAltArrowDownBold as SoCaretCircleDownB,
406
+ DoubleAltArrowUpLinear as SoArrowsVerticalL, DoubleAltArrowUpBold as SoArrowsVerticalB,
407
+ CheckSquareLinear as SoCheckSquareL, CheckSquareBold as SoCheckSquareB,
408
+ ShieldCheckLinear as SoSealCheckL, ShieldCheckBold as SoSealCheckB,
409
+ DocumentsLinear as SoCopySimpleL, DocumentsBold as SoCopySimpleB,
410
+ Widget6Linear as SoGridNineL, Widget6Bold as SoGridNineB,
411
+ Widget3Linear as SoTableL, Widget3Bold as SoTableB,
412
+ WidgetAddLinear as SoGridFourL, WidgetAddBold as SoGridFourB,
413
+ ChecklistLinear as SoTabsL, ChecklistBold as SoTabsB,
414
+ MenuDotsCircleLinear as SoDotsThreeOutlineL, MenuDotsCircleBold as SoDotsThreeOutlineB,
415
+ SortFromTopToBottomLinear as SoCaretUpDownAltL, SortFromTopToBottomBold as SoCaretUpDownAltB,
416
+ BanknoteLinear as SoCoinsL, BanknoteBold as SoCoinsB,
417
+ DocumentLinear as SoArticleL, DocumentBold as SoArticleB,
418
+ Planet2Linear as SoAirplaneAltL, Planet2Bold as SoAirplaneAltB,
419
+ HandHeartLinear as SoHandWavingL, HandHeartBold as SoHandWavingB,
420
+ SquareShareLineLinear as SoStepsL, SquareShareLineBold as SoStepsB,
393
421
  } from "solar-icon-set";
394
422
 
395
423
  // Lucide ──────────────────────────────────────────────────────────
@@ -584,6 +612,17 @@ import {
584
612
  Flower as LuFlower,
585
613
  Leaf as LuLeaf,
586
614
  Trees as LuTree,
615
+ // --- 수렴 분리용 추가 (아래 세트에서만 사용) ---
616
+ CalendarRange as LuCalendarBlank,
617
+ CalendarDays as LuCalendarDots,
618
+ MessagesSquare as LuChatCenteredDots,
619
+ Ellipsis as LuDotsThreeOutline,
620
+ Newspaper as LuArticle,
621
+ FolderClosed as LuFolderSimple,
622
+ BadgeCheck as LuSealBadge,
623
+ SquareDashed as LuPlaceholder,
624
+ Minimize as LuCornersIn,
625
+ Maximize as LuCornersOut,
587
626
  } from "lucide-react";
588
627
 
589
628
  /**
@@ -807,8 +846,8 @@ const solarSet: Partial<Record<IconName, SolarPair>> = {
807
846
  warning: { regular: SoWarningL, fill: SoWarningB },
808
847
  "warning-circle": { regular: SoWarningCircleL, fill: SoWarningCircleB },
809
848
  "check-circle": { regular: SoCheckCircleL, fill: SoCheckCircleB },
810
- "check-square": { regular: SoCheckL, fill: SoCheckB },
811
- "seal-check": { regular: SoCheckCircleL, fill: SoCheckCircleB },
849
+ "check-square": { regular: SoCheckSquareL, fill: SoCheckSquareB },
850
+ "seal-check": { regular: SoSealCheckL, fill: SoSealCheckB },
812
851
  star: { regular: SoStarL, fill: SoStarB },
813
852
  heart: { regular: SoHeartL, fill: SoHeartB },
814
853
  user: { regular: SoUserL, fill: SoUserB },
@@ -829,8 +868,8 @@ const solarSet: Partial<Record<IconName, SolarPair>> = {
829
868
  "caret-up-down": { regular: SoCaretUpDownL, fill: SoCaretUpDownB },
830
869
  "caret-double-left": { regular: SoCaretDoubleLeftL, fill: SoCaretDoubleLeftB },
831
870
  "caret-double-right": { regular: SoCaretDoubleRightL, fill: SoCaretDoubleRightB },
832
- "caret-circle-down": { regular: SoCaretDownL, fill: SoCaretDownB },
833
- "arrows-vertical": { regular: SoCaretUpDownL, fill: SoCaretUpDownB },
871
+ "caret-circle-down": { regular: SoCaretCircleDownL, fill: SoCaretCircleDownB },
872
+ "arrows-vertical": { regular: SoArrowsVerticalL, fill: SoArrowsVerticalB },
834
873
  columns: { regular: SoWidget4L, fill: SoWidget4B },
835
874
  layout: { regular: SoWidgetL, fill: SoWidgetB },
836
875
  house: { regular: SoHomeL, fill: SoHomeB },
@@ -854,9 +893,9 @@ const solarSet: Partial<Record<IconName, SolarPair>> = {
854
893
  textbox: { regular: SoTextL, fill: SoTextB },
855
894
  keyboard: { regular: SoKeyboardL, fill: SoKeyboardB },
856
895
  info: { regular: SoInfoCircleL, fill: SoInfoCircleB },
857
- article: { regular: SoDocumentTextL, fill: SoDocumentTextB },
858
- "grid-four": { regular: SoWidget2L, fill: SoWidget2B },
859
- "grid-nine": { regular: SoWidget5L, fill: SoWidget5B },
896
+ article: { regular: SoArticleL, fill: SoArticleB },
897
+ "grid-four": { regular: SoGridFourL, fill: SoGridFourB },
898
+ "grid-nine": { regular: SoGridNineL, fill: SoGridNineB },
860
899
  selection: { regular: SoSelectionL, fill: SoSelectionB },
861
900
  "radio-button": { regular: SoRadioL, fill: SoRadioB },
862
901
  "toggle-right": { regular: SoRadioL, fill: SoRadioB },
@@ -867,17 +906,17 @@ const solarSet: Partial<Record<IconName, SolarPair>> = {
867
906
  clock: { regular: SoClockL, fill: SoClockB },
868
907
  "upload-simple": { regular: SoUploadL, fill: SoUploadB },
869
908
  "download-simple": { regular: SoDownloadL, fill: SoDownloadB },
870
- table: { regular: SoWidget4L, fill: SoWidget4B },
909
+ table: { regular: SoTableL, fill: SoTableB },
871
910
  cards: { regular: SoCardsL, fill: SoCardsB },
872
911
  "chart-line": { regular: SoChartL, fill: SoChartB },
873
912
  "trend-up": { regular: SoTrendUpL, fill: SoTrendUpB },
874
913
  "trend-down": { regular: SoTrendDownL, fill: SoTrendDownB },
875
- tabs: { regular: SoWidget4L, fill: SoWidget4B },
914
+ tabs: { regular: SoTabsL, fill: SoTabsB },
876
915
  path: { regular: SoPathL, fill: SoPathB },
877
916
  sidebar: { regular: SoSidebarL, fill: SoSidebarB },
878
917
  "sidebar-simple": { regular: SoSidebarSimpleL, fill: SoSidebarSimpleB },
879
918
  "dots-three": { regular: SoDotsThreeL, fill: SoDotsThreeB },
880
- "dots-three-outline": { regular: SoDotsThreeL, fill: SoDotsThreeB },
919
+ "dots-three-outline": { regular: SoDotsThreeOutlineL, fill: SoDotsThreeOutlineB },
881
920
  compass: { regular: SoCompassL, fill: SoCompassB },
882
921
  "chat-circle": { regular: SoChatCircleL, fill: SoChatCircleB },
883
922
  "chat-text": { regular: SoChatTextL, fill: SoChatTextB },
@@ -896,7 +935,7 @@ const solarSet: Partial<Record<IconName, SolarPair>> = {
896
935
  "pencil-simple": { regular: SoPenL, fill: SoPenB },
897
936
  "share-network": { regular: SoShareL, fill: SoShareB },
898
937
  copy: { regular: SoCopyL, fill: SoCopyB },
899
- "copy-simple": { regular: SoCopyL, fill: SoCopyB },
938
+ "copy-simple": { regular: SoCopySimpleL, fill: SoCopySimpleB },
900
939
  scissors: { regular: SoScissorsL, fill: SoScissorsB },
901
940
  "clipboard-text": { regular: SoClipboardTextL, fill: SoClipboardTextB },
902
941
  camera: { regular: SoCameraL, fill: SoCameraB },
@@ -905,7 +944,7 @@ const solarSet: Partial<Record<IconName, SolarPair>> = {
905
944
  placeholder: { regular: SoSquareL, fill: SoSquareB },
906
945
  square: { regular: SoSquareL, fill: SoSquareB },
907
946
  "square-half": { regular: SoSquareL, fill: SoSquareB },
908
- steps: { regular: SoPathL, fill: SoPathB },
947
+ steps: { regular: SoStepsL, fill: SoStepsB },
909
948
  "line-segments": { regular: SoLineSegmentsL, fill: SoLineSegmentsB },
910
949
  "paint-bucket": { regular: SoPaintBucketL, fill: SoPaintBucketB },
911
950
  "split-horizontal": { regular: SoSplitHorizontalL, fill: SoSplitHorizontalB },
@@ -916,9 +955,9 @@ const solarSet: Partial<Record<IconName, SolarPair>> = {
916
955
  file: { regular: SoFileL, fill: SoFileB },
917
956
  "file-text": { regular: SoDocumentTextL, fill: SoDocumentTextB },
918
957
  link: { regular: SoLinkL, fill: SoLinkB },
919
- "link-simple": { regular: SoLinkL, fill: SoLinkB },
958
+ "link-simple": { regular: SoLinkSimpleL, fill: SoLinkSimpleB },
920
959
  lock: { regular: SoLockL, fill: SoLockB },
921
- "lock-open": { regular: SoLockL, fill: SoLockB },
960
+ "lock-open": { regular: SoLockOpenL, fill: SoLockOpenB },
922
961
  key: { regular: SoKeyL, fill: SoKeyB },
923
962
  "sign-out": { regular: SoSignOutL, fill: SoSignOutB },
924
963
  "sign-in": { regular: SoSignInL, fill: SoSignInB },
@@ -946,12 +985,12 @@ const solarSet: Partial<Record<IconName, SolarPair>> = {
946
985
  "arrow-down": { regular: SoArrowDownL, fill: SoArrowDownB },
947
986
  "arrow-clockwise": { regular: SoArrowClockwiseL, fill: SoArrowClockwiseB },
948
987
  "arrow-counter-clockwise": { regular: SoArrowCCWL, fill: SoArrowCCWB },
949
- "arrows-clockwise": { regular: SoArrowClockwiseL, fill: SoArrowClockwiseB },
988
+ "arrows-clockwise": { regular: SoArrowsClockwiseL, fill: SoArrowsClockwiseB },
950
989
  "arrows-left-right": { regular: SoArrowsLeftRightL, fill: SoArrowsLeftRightB },
951
990
  "arrows-out": { regular: SoArrowsOutL, fill: SoArrowsOutB },
952
991
  "arrows-in": { regular: SoArrowsInL, fill: SoArrowsInB },
953
- "corners-out": { regular: SoArrowsOutL, fill: SoArrowsOutB },
954
- "corners-in": { regular: SoArrowsInL, fill: SoArrowsInB },
992
+ "corners-out": { regular: SoCornersOutL, fill: SoCornersOutB },
993
+ "corners-in": { regular: SoCornersInL, fill: SoCornersInB },
955
994
  play: { regular: SoPlayL, fill: SoPlayB },
956
995
  pause: { regular: SoPauseL, fill: SoPauseB },
957
996
  stop: { regular: SoStopL, fill: SoStopB },
@@ -976,26 +1015,26 @@ const solarSet: Partial<Record<IconName, SolarPair>> = {
976
1015
  "credit-card": { regular: SoCardL, fill: SoCardB },
977
1016
  wallet: { regular: SoWalletL, fill: SoWalletB },
978
1017
  receipt: { regular: SoBillL, fill: SoBillB },
979
- coins: { regular: SoDollarL, fill: SoDollarB },
1018
+ coins: { regular: SoCoinsL, fill: SoCoinsB },
980
1019
  buildings: { regular: SoBuildingsL, fill: SoBuildingsB },
981
- factory: { regular: SoBuildingsL, fill: SoBuildingsB },
1020
+ factory: { regular: SoFactoryL, fill: SoFactoryB },
982
1021
  storefront: { regular: SoStorefrontL, fill: SoStorefrontB },
983
1022
  truck: { regular: SoTruckL, fill: SoTruckB },
984
- airplane: { regular: SoPaperPlaneL, fill: SoPaperPlaneB },
1023
+ airplane: { regular: SoAirplaneAltL, fill: SoAirplaneAltB },
985
1024
  car: { regular: SoTruckL, fill: SoTruckB },
986
1025
  bicycle: { regular: SoBicycleL, fill: SoBicycleB },
987
1026
  "map-trifold": { regular: SoMapTrifoldL, fill: SoMapTrifoldB },
988
- navigation: { regular: SoCompassL, fill: SoCompassB },
1027
+ navigation: { regular: SoNavigationL, fill: SoNavigationB },
989
1028
  shield: { regular: SoShieldL, fill: SoShieldB },
990
1029
  "shield-check": { regular: SoShieldCheckL, fill: SoShieldCheckB },
991
1030
  lifebuoy: { regular: SoLifebuoyL, fill: SoLifebuoyB },
992
1031
  question: { regular: SoQuestionL, fill: SoQuestionB },
993
- smiley: { regular: SoSmileyL, fill: SoSmileyB },
994
- "smiley-meh": { regular: SoSmileyL, fill: SoSmileyB },
995
- "smiley-sad": { regular: SoSmileyL, fill: SoSmileyB },
1032
+ smiley: { regular: SoSmileyHappyL, fill: SoSmileyHappyB },
1033
+ "smiley-meh": { regular: SoSmileyMehL, fill: SoSmileyMehB },
1034
+ "smiley-sad": { regular: SoSmileySadL, fill: SoSmileySadB },
996
1035
  "thumbs-up": { regular: SoThumbsUpL, fill: SoThumbsUpB },
997
1036
  "thumbs-down": { regular: SoThumbsDownL, fill: SoThumbsDownB },
998
- "hand-waving": { regular: SoHeartL, fill: SoHeartB },
1037
+ "hand-waving": { regular: SoHandWavingL, fill: SoHandWavingB },
999
1038
  trophy: { regular: SoTrophyL, fill: SoTrophyB },
1000
1039
  medal: { regular: SoMedalL, fill: SoMedalB },
1001
1040
  crown: { regular: SoCrownL, fill: SoCrownB },
@@ -1011,7 +1050,7 @@ const lucideSet: Partial<Record<IconName, AnyComp>> = {
1011
1050
  "warning-circle": LuWarningCircle,
1012
1051
  "check-circle": LuCheckCircle,
1013
1052
  "check-square": LuCheckSquare,
1014
- "seal-check": LuSealCheck,
1053
+ "seal-check": LuSealBadge,
1015
1054
  star: LuStar,
1016
1055
  heart: LuHeart,
1017
1056
  user: LuUser,
@@ -1036,7 +1075,7 @@ const lucideSet: Partial<Record<IconName, AnyComp>> = {
1036
1075
  "arrows-vertical": LuArrowsVertical,
1037
1076
  columns: LuColumns,
1038
1077
  square: LuSquare,
1039
- placeholder: LuSquare,
1078
+ placeholder: LuPlaceholder,
1040
1079
  rectangle: LuRectangle,
1041
1080
  layout: LuLayout,
1042
1081
  house: LuHouse,
@@ -1058,8 +1097,8 @@ const lucideSet: Partial<Record<IconName, AnyComp>> = {
1058
1097
  "toggle-right": LuToggleRight,
1059
1098
  "toggle-left": LuToggleLeft,
1060
1099
  calendar: LuCalendar,
1061
- "calendar-blank": LuCalendar,
1062
- "calendar-dots": LuCalendar,
1100
+ "calendar-blank": LuCalendarBlank,
1101
+ "calendar-dots": LuCalendarDots,
1063
1102
  clock: LuClock,
1064
1103
  "upload-simple": LuUpload,
1065
1104
  "download-simple": LuDownload,
@@ -1078,7 +1117,7 @@ const lucideSet: Partial<Record<IconName, AnyComp>> = {
1078
1117
  sidebar: LuSidebar,
1079
1118
  "sidebar-simple": LuSidebarSimple,
1080
1119
  "dots-three": LuDotsThree,
1081
- "dots-three-outline": LuDotsThree,
1120
+ "dots-three-outline": LuDotsThreeOutline,
1082
1121
  compass: LuCompass,
1083
1122
  "chat-circle": LuChatCircle,
1084
1123
  "chat-text": LuChatText,
@@ -1101,7 +1140,7 @@ const lucideSet: Partial<Record<IconName, AnyComp>> = {
1101
1140
  "squares-four": LuGrid3X3,
1102
1141
  list: LuList,
1103
1142
  info: LuInfo,
1104
- article: LuFileText,
1143
+ article: LuArticle,
1105
1144
  "grid-four": LuLayoutGrid,
1106
1145
  "arrow-square-out": LuExternalLink,
1107
1146
  "pencil-simple": LuPencil,
@@ -1115,7 +1154,7 @@ const lucideSet: Partial<Record<IconName, AnyComp>> = {
1115
1154
  "square-half": LuSquareHalf,
1116
1155
  folder: LuFolder,
1117
1156
  "folder-open": LuFolderOpen,
1118
- "folder-simple": LuFolder,
1157
+ "folder-simple": LuFolderSimple,
1119
1158
  file: LuFile,
1120
1159
  "file-text": LuFileText,
1121
1160
  link: LuLink,
@@ -1131,7 +1170,7 @@ const lucideSet: Partial<Record<IconName, AnyComp>> = {
1131
1170
  "map-pin": LuMapPin,
1132
1171
  "push-pin": LuPushPin,
1133
1172
  "paper-plane": LuPaperPlane,
1134
- "chat-centered-dots": LuChatText,
1173
+ "chat-centered-dots": LuChatCenteredDots,
1135
1174
  hash: LuHash,
1136
1175
  at: LuAt,
1137
1176
  bookmark: LuBookmark,
@@ -1153,8 +1192,8 @@ const lucideSet: Partial<Record<IconName, AnyComp>> = {
1153
1192
  "arrows-left-right": LuArrowsLeftRight,
1154
1193
  "arrows-out": LuArrowsOut,
1155
1194
  "arrows-in": LuArrowsIn,
1156
- "corners-out": LuArrowsOut,
1157
- "corners-in": LuArrowsIn,
1195
+ "corners-out": LuCornersOut,
1196
+ "corners-in": LuCornersIn,
1158
1197
  play: LuPlay,
1159
1198
  pause: LuPause,
1160
1199
  stop: LuStop,
@@ -0,0 +1,339 @@
1
+ /*
2
+ * Kanban — 보드 / 컬럼 / 카드 3-레벨.
3
+ *
4
+ * CSS 변수 조절점:
5
+ * --kanban-column-width 컬럼 1장 width
6
+ * --kanban-column-gap 컬럼 사이 가로 간격
7
+ * --kanban-column-pad 컬럼 내부 padding
8
+ * --kanban-card-pad 카드 내부 padding
9
+ * --kanban-card-gap 카드 안 slot 세로 gap
10
+ * --kanban-stack-gap 한 컬럼 안 카드 세로 gap
11
+ *
12
+ * layout 축:
13
+ * wrap — 컬럼 자체가 chrome(배경/테두리)을 가지고 header·body가 안에 함께 들어감.
14
+ * stack — 컬럼 자체엔 chrome 없고 header와 body가 각자 자체 chrome을 가진
15
+ * 두 블록으로 세로 분리. header가 chrome 바깥 위에 "얹어진" 모습.
16
+ */
17
+
18
+ /* ──────────────────────────────────────────────────────
19
+ Board
20
+ ──────────────────────────────────────────────────── */
21
+
22
+ .board {
23
+ /* Kanban 컬럼 전용 폭 — 공용 space 스케일에 등가 토큰 없음, 로컬 상수로 선언. */
24
+ --kanban-column-width: 320px; /* lint-hardcoded: ignore */
25
+ --kanban-column-gap: var(--space-3);
26
+ --kanban-column-pad: var(--space-3);
27
+ --kanban-stack-gap: var(--space-2);
28
+
29
+ display: flex;
30
+ gap: var(--kanban-column-gap);
31
+ align-items: stretch;
32
+ min-width: 0;
33
+ }
34
+
35
+ .board.scroll {
36
+ overflow-x: auto;
37
+ overflow-y: hidden;
38
+ padding-bottom: var(--space-1);
39
+ }
40
+
41
+ /* scroll=false: 가로 스크롤 끄되 wrap하지 않음. 칸반은 무조건 로우. */
42
+ .board.noscroll {
43
+ overflow: visible;
44
+ }
45
+
46
+ /* ──────────────────────────────────────────────────────
47
+ Column — 공통 뼈대
48
+ ──────────────────────────────────────────────────── */
49
+
50
+ .column {
51
+ position: relative;
52
+ flex: 0 0 var(--kanban-column-width);
53
+ width: var(--kanban-column-width);
54
+ max-width: 100%;
55
+ min-width: 0;
56
+ display: flex;
57
+ flex-direction: column;
58
+ color: var(--fg);
59
+ }
60
+
61
+ /* scroll=false면 각 컬럼이 남는 공간을 균등 분할. 로우 유지. */
62
+ .board.noscroll .column {
63
+ flex: 1 1 var(--kanban-column-width);
64
+ }
65
+
66
+ /* ──────────────────────────────────────────────────────
67
+ layout=wrap — 컬럼 자체가 chrome 가짐. header/body 공통 쉘.
68
+ ──────────────────────────────────────────────────── */
69
+
70
+ .layout-wrap {
71
+ gap: var(--space-2);
72
+ padding: var(--kanban-column-pad);
73
+ border-radius: var(--radius-lg);
74
+ transition: var(--transition-colors);
75
+ }
76
+
77
+ /* chrome 축 — layout=wrap. [[feedback_bg_or_stroke_only]]: 배경만 or 테두리만. */
78
+ .layout-wrap.chrome-line {
79
+ background: transparent;
80
+ border: 1px solid var(--border);
81
+ }
82
+ .layout-wrap.chrome-filled {
83
+ background: var(--column-fill, var(--bg-muted));
84
+ }
85
+ .layout-wrap.chrome-plain {
86
+ background: transparent;
87
+ padding: 0;
88
+ }
89
+
90
+ /* tone별 fill 색 — chrome=filled일 때 적용됨.
91
+ neutral은 중립 bg-muted(기본값), 나머지는 base color 4% opacity.
92
+ 글로벌 *-subtle(8%)보다 더 연하게 — 컬럼은 "면"이라 subtle보다 조용해야 함. */
93
+ .column[data-tone="primary"] { --column-fill: color-mix(in oklab, var(--primary) 4%, transparent); }
94
+ .column[data-tone="success"] { --column-fill: color-mix(in oklab, var(--success) 4%, transparent); }
95
+ .column[data-tone="warning"] { --column-fill: color-mix(in oklab, var(--warning) 4%, transparent); }
96
+ .column[data-tone="danger"] { --column-fill: color-mix(in oklab, var(--destructive) 4%, transparent); }
97
+ .column[data-tone="info"] { --column-fill: color-mix(in oklab, var(--info) 4%, transparent); }
98
+
99
+ /* chrome=filled일 때 header 안 텍스트·아이콘도 tone 색계열로 (fill 색 full opacity).
100
+ neutral은 기본 fg-strong 유지.
101
+ action 안 IconButton까지 색이 번지도록 자손 svg·button까지 상속. */
102
+ .chrome-filled[data-tone="primary"] .columnHeader,
103
+ .chrome-filled[data-tone="primary"] .columnHeader * { color: var(--primary); }
104
+ .chrome-filled[data-tone="success"] .columnHeader,
105
+ .chrome-filled[data-tone="success"] .columnHeader * { color: var(--success); }
106
+ .chrome-filled[data-tone="warning"] .columnHeader,
107
+ .chrome-filled[data-tone="warning"] .columnHeader * { color: var(--warning); }
108
+ .chrome-filled[data-tone="danger"] .columnHeader,
109
+ .chrome-filled[data-tone="danger"] .columnHeader * { color: var(--destructive); }
110
+ .chrome-filled[data-tone="info"] .columnHeader,
111
+ .chrome-filled[data-tone="info"] .columnHeader * { color: var(--info); }
112
+
113
+ /* ──────────────────────────────────────────────────────
114
+ layout=stack — header만 chrome. body(카드 스택)는 chrome 없음.
115
+ header가 그릇 바깥 위에 "얹어진" 모습 — 카드들은 그 아래 분리된 공간.
116
+ ──────────────────────────────────────────────────── */
117
+
118
+ .layout-stack {
119
+ gap: var(--space-2);
120
+ background: transparent;
121
+ padding: 0;
122
+ }
123
+
124
+ /* stack: header만 chrome 보유 */
125
+ .layout-stack .columnHeader {
126
+ padding: var(--space-2) var(--space-3);
127
+ border-radius: var(--radius-md);
128
+ transition: var(--transition-colors);
129
+ position: relative;
130
+ }
131
+
132
+ /* stack: body는 chrome 없음. 카드 스택만. */
133
+ .layout-stack .columnBody {
134
+ padding: 0;
135
+ }
136
+
137
+ /* chrome 축 — layout=stack: header에만 적용 */
138
+ .layout-stack.chrome-line .columnHeader {
139
+ background: transparent;
140
+ border: 1px solid var(--border);
141
+ }
142
+ .layout-stack.chrome-filled .columnHeader {
143
+ background: var(--column-fill, var(--bg-muted));
144
+ }
145
+ .layout-stack.chrome-plain .columnHeader {
146
+ padding: 0 var(--space-1);
147
+ }
148
+
149
+ /* ──────────────────────────────────────────────────────
150
+ Column header (공통)
151
+ ──────────────────────────────────────────────────── */
152
+
153
+ .columnHeader {
154
+ display: flex;
155
+ align-items: center;
156
+ gap: var(--space-2);
157
+ min-width: 0;
158
+ padding-inline: var(--space-1);
159
+ }
160
+
161
+ .columnTitle {
162
+ font-size: var(--text-base);
163
+ font-weight: var(--font-weight-medium);
164
+ color: var(--fg-strong, var(--fg));
165
+ line-height: var(--lh-base);
166
+ min-width: 0;
167
+ overflow: hidden;
168
+ text-overflow: ellipsis;
169
+ white-space: nowrap;
170
+ }
171
+
172
+ .columnCount {
173
+ font-size: var(--text-xs);
174
+ color: var(--fg-muted);
175
+ font-variant-numeric: tabular-nums;
176
+ flex-shrink: 0;
177
+ margin-left: calc(var(--space-2) * -1 + var(--space-1));
178
+ margin-right: auto;
179
+ }
180
+
181
+ .columnAction {
182
+ display: inline-flex;
183
+ align-items: center;
184
+ gap: var(--space-1);
185
+ flex-shrink: 0;
186
+ color: var(--fg-muted);
187
+ }
188
+
189
+ /* ──────────────────────────────────────────────────────
190
+ Accent (tone 색 지점)
191
+ ──────────────────────────────────────────────────── */
192
+
193
+ .accentMark {
194
+ flex-shrink: 0;
195
+ background: var(--column-accent, var(--fg-muted));
196
+ }
197
+
198
+ .accentMark[data-accent="dot"] {
199
+ width: var(--space-2);
200
+ height: var(--space-2);
201
+ border-radius: var(--radius-full);
202
+ }
203
+
204
+ .column[data-tone="neutral"] { --column-accent: var(--fg-muted); }
205
+ .column[data-tone="primary"] { --column-accent: var(--primary); }
206
+ .column[data-tone="success"] { --column-accent: var(--success); }
207
+ .column[data-tone="warning"] { --column-accent: var(--warning); }
208
+ .column[data-tone="danger"] { --column-accent: var(--destructive); }
209
+ .column[data-tone="info"] { --column-accent: var(--info); }
210
+
211
+ /* ──────────────────────────────────────────────────────
212
+ Column body (카드 스택)
213
+ ──────────────────────────────────────────────────── */
214
+
215
+ .columnBody {
216
+ display: flex;
217
+ flex-direction: column;
218
+ gap: var(--kanban-stack-gap);
219
+ min-height: var(--space-8);
220
+ border-radius: var(--radius-md);
221
+ transition: var(--transition-colors);
222
+ }
223
+
224
+
225
+ .columnFooter {
226
+ padding-top: var(--space-1);
227
+ color: var(--fg-muted);
228
+ }
229
+
230
+ /* ──────────────────────────────────────────────────────
231
+ Card
232
+ ──────────────────────────────────────────────────── */
233
+
234
+ .card {
235
+ --kanban-card-pad: var(--space-3);
236
+ --kanban-card-gap: var(--space-2);
237
+
238
+ display: flex;
239
+ flex-direction: column;
240
+ gap: var(--kanban-card-gap);
241
+ padding: var(--kanban-card-pad);
242
+ background: color-mix(in oklab, var(--bg) 80%, transparent);
243
+ border-radius: var(--radius-md);
244
+ color: var(--fg);
245
+ text-decoration: none;
246
+ min-width: 0;
247
+ transition: var(--transition-colors), transform var(--duration-base) var(--ease-out),
248
+ box-shadow var(--duration-base) var(--ease-out);
249
+ }
250
+
251
+ .card:hover {
252
+ background: var(--bg);
253
+ border-color: var(--border-strong);
254
+ transform: translateY(calc(var(--space-0_5) * -1));
255
+ box-shadow: var(--shadow-md);
256
+ }
257
+
258
+ .cardInteractive {
259
+ cursor: pointer;
260
+ }
261
+ .cardInteractive:focus-visible {
262
+ outline: none;
263
+ box-shadow: var(--ring-shadow);
264
+ }
265
+
266
+ /* ── Card slots ────────────────────────────────────── */
267
+
268
+ .cover {
269
+ margin: calc(var(--kanban-card-pad) * -1) calc(var(--kanban-card-pad) * -1) 0;
270
+ border-top-left-radius: inherit;
271
+ border-top-right-radius: inherit;
272
+ overflow: hidden;
273
+ display: block;
274
+ }
275
+ .cover > img,
276
+ .cover > video {
277
+ display: block;
278
+ width: 100%;
279
+ height: auto;
280
+ }
281
+
282
+ .cardHeader {
283
+ display: flex;
284
+ align-items: center;
285
+ gap: var(--space-2);
286
+ min-width: 0;
287
+ color: var(--fg-muted);
288
+ }
289
+
290
+ .cardTitle {
291
+ font-size: var(--text-sm);
292
+ line-height: var(--lh-sm);
293
+ color: var(--fg-strong, var(--fg));
294
+ font-weight: var(--font-weight-medium);
295
+ min-width: 0;
296
+ display: flex;
297
+ flex-wrap: wrap;
298
+ align-items: center;
299
+ gap: var(--space-2);
300
+ }
301
+
302
+ .cardDescription {
303
+ margin: 0;
304
+ font-size: var(--text-sm);
305
+ line-height: var(--lh-sm);
306
+ color: var(--fg-muted);
307
+ font-weight: var(--font-weight-regular);
308
+ display: -webkit-box;
309
+ -webkit-line-clamp: 3;
310
+ -webkit-box-orient: vertical;
311
+ overflow: hidden;
312
+ }
313
+
314
+ /* title 바로 뒤의 description — 둘은 한 묶음으로 간주해 gap 좁힘.
315
+ card의 기본 gap(space-2)에서 space-1만큼 당겨 space-1(=4px)로 유지. */
316
+ .cardTitle + .cardDescription {
317
+ margin-top: calc(var(--space-1) * -1);
318
+ }
319
+
320
+ .cardMeta {
321
+ display: flex;
322
+ align-items: center;
323
+ flex-wrap: wrap;
324
+ gap: var(--space-2);
325
+ font-size: var(--text-xs);
326
+ line-height: var(--lh-sm);
327
+ color: var(--fg-subtle);
328
+ font-variant-numeric: tabular-nums;
329
+ }
330
+
331
+ .cardFooter {
332
+ display: flex;
333
+ align-items: center;
334
+ justify-content: space-between;
335
+ gap: var(--space-2);
336
+ color: var(--fg-muted);
337
+ font-size: var(--text-xs);
338
+ line-height: var(--lh-sm);
339
+ }