From 2394c1306596346c6b845a64c1d827bb28cb52da Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Tue, 7 Nov 2023 21:27:11 +0700 Subject: [PATCH] ui: standalone UIKit and refactor (#557) * Eslint import order * Initial Uikit * Rename file with camelCase * Remove unused code * Remove unused code * Set position traficlight mac * Grouping Ribbon, Topbar and Bottombar as layout * Added image brand * Moving feature toggle into context folder * Fix active state of setting menu * Cleanup downloadModel atom helper * Cleanup useGetConfigureModel * Added wave animation * Create useMainViewState intead of import helper atom * Remove unused code * Take a back switch ui * Toggle using switch component * Add dynamic primary color * Cleanup import * Added uikit scroll area * Add best practice form * Added toaster container * Fix loader container * Add hooks useDownloadState * Added tooltip on ribbon menu * Added case user multiple download model * Adjust input style with bigger ring * Restyle my model screen * Replace useStartStop model with useActiveModel * Import icon using Icon name * Fix missing login loading start and stop model * WIP integrate with cmdk * Move layout search bar on middle of app * Added function cancel download * Cleanup model explore * Cleanup unused code * Move app version in bototmbar or footer * WIP chat screen * WIP chat screen * Cleanup style and remove unsed code * Added command for showing downloaded model * Fix missing keyframe loader dot animation * Conditional loader of plugin setting * WIP history list message * chore: rebase main * Adding script ui into root package * Fix different version react hooks form * Add close toaster * Added status model active or not on list of command * Conditional showing info if user don't have a model * Disabled toolbar chat when user not yet have convo * chore: fix state * fix: get resource atom * Fix conditional bottom bar * fix: model download state * Fix font * Improve icon my model * Add toaster delete chat * Remove test classname * Fix scroll chat body * Fix scrolling chat body * chore: add message update * Add uikit into depedencies on root package * Update chat flow * Fix hot reload ui changes * Increate background color chat screen light mode * Added visual conversation active state * Added build:uikit on gh actions * chore: attempt to fix CI * fix: deps * fix: tests * chore: attempt to fix CI --------- Co-authored-by: Louis --- .../jan-electron-linter-and-test.yml | 46 +- electron/main.ts | 5 +- electron/tests/explore.e2e.spec.ts | 8 +- electron/tests/my-models.e2e.spec.ts | 2 +- package.json | 19 +- uikit/.prettierignore | 5 + uikit/.prettierrc | 8 + uikit/package.json | 53 +++ uikit/postcss.config.js | 8 + uikit/src/avatar/index.tsx | 43 ++ uikit/src/avatar/styles.scss | 11 + uikit/src/badge/index.tsx | 30 ++ uikit/src/badge/styles.scss | 23 + uikit/src/button/index.tsx | 98 +++++ uikit/src/button/styles.scss | 64 +++ uikit/src/command/index.tsx | 132 ++++++ uikit/src/command/styles.scss | 45 ++ uikit/src/form/index.tsx | 175 ++++++++ uikit/src/form/styles.scss | 21 + uikit/src/index.ts | 11 + uikit/src/input/index.tsx | 21 + uikit/src/input/styles.scss | 6 + uikit/src/main.scss | 116 +++++ uikit/src/modal/index.tsx | 99 +++++ uikit/src/modal/styles.scss | 32 ++ uikit/src/progress/index.tsx | 24 ++ uikit/src/progress/styles.scss | 7 + uikit/src/scroll-area/index.tsx | 51 +++ uikit/src/scroll-area/styles.scss | 23 + uikit/src/switch/index.tsx | 22 + uikit/src/switch/styles.scss | 10 + uikit/src/tooltip/index.tsx | 40 ++ uikit/src/tooltip/styles.scss | 6 + uikit/tailwind.config.js | 32 ++ uikit/tsconfig.json | 24 ++ uikit/types/declaration.d.ts | 4 + web/.eslintrc.js | 144 +++++++ web/.eslintrc.json | 6 - web/.prettierrc | 2 +- .../_components/ActiveModelTable/index.tsx | 19 - .../_components/AvailableModelCard/index.tsx | 66 --- web/app/_components/Avatar/index.tsx | 23 - .../_components/BasicPromptButton/index.tsx | 20 - web/app/_components/BotInfo/index.tsx | 58 --- .../_components/BotInfoContainer/index.tsx | 69 --- .../_components/BotListContainer/index.tsx | 63 --- web/app/_components/BotListModal/index.tsx | 48 --- web/app/_components/BotPreview/index.tsx | 26 -- web/app/_components/BotSetting/index.tsx | 169 -------- web/app/_components/CenterContainer/index.tsx | 12 - .../ChatBody/renderChatMessage.tsx | 54 --- web/app/_components/ChatItem/index.tsx | 19 - .../ConfirmDeleteModelModal/index.tsx | 85 ---- .../_components/ConfirmSignOutModal/index.tsx | 89 ---- .../_components/ConversationalCard/index.tsx | 44 -- .../_components/ConversationalList/index.tsx | 25 -- .../_components/CreateBotContainer/index.tsx | 175 -------- .../_components/CreateBotInAdvance/index.tsx | 98 ----- .../CreateBotPromptInput/index.tsx | 46 -- .../CustomBotTemperature/index.tsx | 41 -- .../DownloadModelContent/index.tsx | 58 --- .../_components/DownloadModelTitle/index.tsx | 13 - .../_components/DownloadedModelCard/index.tsx | 35 -- .../DownloadedModelTable/index.tsx | 21 - .../DownloadingModelTable/index.tsx | 28 -- .../DraggableProgressBar/index.tsx | 48 --- web/app/_components/DropdownBox/index.tsx | 40 -- web/app/_components/DropdownList/index.tsx | 59 --- .../_components/EmptyChatContainer/index.tsx | 14 - .../_components/ExpandableHeader/index.tsx | 13 - .../ExploreModelContainer/index.tsx | 19 - .../_components/ExploreModelFilter/index.tsx | 41 -- .../_components/ExploreModelItem/index.tsx | 153 ------- .../ExploreModelItemHeader/index.tsx | 117 ------ web/app/_components/HamburgerButton/index.tsx | 22 - web/app/_components/Header/index.tsx | 19 - .../_components/HeaderBackButton/index.tsx | 13 - web/app/_components/HeaderTitle/index.tsx | 16 - web/app/_components/LeftContainer/index.tsx | 43 -- .../_components/LeftHeaderAction/index.tsx | 77 ---- web/app/_components/LeftRibbonNav/index.tsx | 116 ----- web/app/_components/LoginButton/index.tsx | 24 -- web/app/_components/MainChat/index.tsx | 11 - web/app/_components/MainContainer/index.tsx | 22 - web/app/_components/MainView/index.tsx | 48 --- web/app/_components/MenuHeader/index.tsx | 53 --- web/app/_components/MobileMenuPane/index.tsx | 60 --- .../_components/ModelActionButton/index.tsx | 61 --- web/app/_components/ModelActionMenu/index.tsx | 15 - .../_components/ModelDownloadButton/index.tsx | 21 - .../ModelDownloadingButton/index.tsx | 23 - .../_components/ModelDownloadingRow/index.tsx | 36 -- .../ModelDownloadingTable/index.tsx | 33 -- web/app/_components/ModelInfoItem/index.tsx | 15 - web/app/_components/ModelRow/index.tsx | 72 ---- web/app/_components/ModelSearchBar/index.tsx | 31 -- web/app/_components/ModelSelector/index.tsx | 118 ------ .../ModelStatusComponent/index.tsx | 46 -- web/app/_components/ModelTable/index.tsx | 34 -- .../_components/ModelTableHeader/index.tsx | 16 - .../_components/ModelVersionItem/index.tsx | 85 ---- web/app/_components/MonitorBar/index.tsx | 48 --- .../_components/MyModelContainer/index.tsx | 17 - web/app/_components/Preferences.tsx | 397 ------------------ web/app/_components/PrimaryButton/index.tsx | 29 -- web/app/_components/ProgressSetting/index.tsx | 42 -- web/app/_components/RightContainer/index.tsx | 54 --- web/app/_components/SearchBar/index.tsx | 45 -- web/app/_components/SecondaryButton/index.tsx | 31 -- .../_components/SessionProviderWrapper.tsx | 11 - web/app/_components/SidebarFooter/index.tsx | 23 - web/app/_components/SidebarHeader/index.tsx | 10 - web/app/_components/SidebarMenuItem/index.tsx | 41 -- web/app/_components/SimpleCheckbox/index.tsx | 22 - .../_components/SimpleControlNetMessage.tsx | 67 --- .../_components/SimpleImageMessage/index.tsx | 72 ---- .../_components/SimpleTag/TagStyleMapper.ts | 22 - web/app/_components/SimpleTag/index.tsx | 39 -- .../_components/SimpleTextMessage/index.tsx | 85 ---- .../_components/TextInputWithTitle/index.tsx | 40 -- web/app/_components/ToggleSwitch/index.tsx | 51 --- .../_components/UserProfileDropDown/index.tsx | 36 -- .../ViewModelDetailButton/index.tsx | 21 - .../_components/WelcomeContainer/index.tsx | 34 -- web/app/layout.tsx | 28 +- web/app/page.tsx | 51 +-- web/app/privacy/page.tsx | 4 +- web/app/support/page.tsx | 4 +- .../BasicPromptAccessories/index.tsx | 7 - .../BasicPromptInput/index.tsx | 20 +- .../ConfirmDeleteConversationModal/index.tsx | 10 +- .../ConfirmationModal/index.tsx | 8 +- .../HistoryItem/index.tsx | 42 +- .../HistoryList/index.tsx | 19 +- .../InputToolbar/index.tsx | 59 +-- .../LoadingIndicator.tsx | 0 .../MainHeader/index.tsx | 16 +- .../ModalNoActiveModel/index.tsx | 18 +- .../ProgressBar/index.tsx | 0 .../SendButton/index.tsx | 19 +- .../SidebarEmptyHistory/index.tsx | 32 +- .../SwitchingModelConfirmationModal/index.tsx | 17 +- .../TextAreaWithTitle/index.tsx | 5 +- web/constants/screens.ts | 7 + .../TagType.ts => constants/tagType.ts} | 0 web/containers/BottomBar/index.tsx | 72 ---- web/containers/Brand/Logo/Mark.tsx | 20 + .../BottomBar/DownloadingState/index.tsx | 87 ++++ .../Layout/BottomBar/SystemItem/index.tsx | 15 + web/containers/Layout/BottomBar/index.tsx | 81 ++++ web/containers/Layout/Ribbon/index.tsx | 152 +++++++ .../CommandListDownloadedModel/index.tsx | 99 +++++ .../Layout/TopBar/CommandSearch/index.tsx | 124 ++++++ web/containers/Layout/TopBar/index.tsx | 23 + web/containers/Layout/index.tsx | 39 +- web/containers/Loader/index.tsx | 30 +- web/containers/Logo/CompactLogo/index.tsx | 22 - web/containers/ModalCancelDownload/index.tsx | 85 ++++ .../Providers}/EventHandler.tsx | 63 ++- .../Providers/EventListener.tsx} | 54 ++- .../Providers/Jotai.tsx} | 19 +- .../Providers/Theme.tsx} | 16 +- web/containers/Providers/index.tsx | 53 +-- web/containers/Sidebar/Left.tsx | 201 --------- web/containers/Sidebar/Right.tsx | 12 - web/containers/Sidebar/index.tsx | 2 - web/containers/SystemItem/index.tsx | 13 - web/containers/Toast/index.tsx | 52 +++ web/containers/Topbar/index.tsx | 51 --- .../FeatureToggle.tsx} | 13 +- web/helpers/ModalWrapper.tsx | 16 +- web/helpers/atoms/Bot.atom.ts | 3 - web/helpers/atoms/ChatMessage.atom.ts | 1 + web/helpers/atoms/Conversation.atom.ts | 14 +- web/helpers/atoms/DownloadState.atom.ts | 34 -- web/helpers/atoms/DownloadedModel.atom.ts | 7 - web/helpers/atoms/ExploreModelLoading.atom.ts | 3 - web/helpers/atoms/MainView.atom.ts | 55 --- web/helpers/atoms/Modal.atom.ts | 3 +- web/helpers/atoms/Model.atom.ts | 6 +- web/helpers/atoms/SideBarExpand.atom.ts | 8 - web/helpers/atoms/SystemBar.atom.ts | 6 - web/helpers/withAnalytics.tsx | 13 - web/hooks/useActiveModel.ts | 96 +++++ web/hooks/useBodyClass.ts | 22 + web/hooks/useCreateBot.ts | 12 - web/hooks/useCreateConversation.ts | 46 +- web/hooks/useDeleteBot.ts | 23 - web/hooks/useDeleteConversation.ts | 33 +- web/hooks/useDeleteModel.ts | 19 +- web/hooks/useDownloadModel.ts | 24 +- web/hooks/useDownloadState.ts | 67 +++ web/hooks/useGetAppVersion.ts | 2 +- web/hooks/useGetBots.ts | 25 -- web/hooks/useGetConfiguredModels.ts | 20 +- web/hooks/useGetCurrentUser.ts | 53 --- web/hooks/useGetDownloadedModels.ts | 26 +- web/hooks/useGetHuggingFaceModel.ts | 35 -- web/hooks/useGetInputState.ts | 21 +- web/hooks/useGetMostSuitableModelVersion.ts | 6 +- web/hooks/useGetPerformanceTag.ts | 8 +- web/hooks/useGetSystemResources.ts | 11 +- web/hooks/useGetUserConversations.ts | 19 +- web/hooks/useMainViewState.ts | 11 + web/hooks/useSendChatMessage.ts | 51 ++- web/hooks/useSignIn.ts | 9 - web/hooks/useSignOut.ts | 14 - web/hooks/useStartStopModel.ts | 66 --- web/hooks/useUpdateBot.ts | 34 -- web/hooks/useUserConfigs.ts | 7 +- web/models/ChatMessage.ts | 8 +- web/models/User.ts | 6 - web/next.config.js | 12 +- web/package.json | 57 +-- web/plugin/Plugin.ts | 5 - web/plugin/PluginManager.ts | 12 +- web/plugin/index.ts | 1 + web/screens/Bot/index.tsx | 13 - .../Chat}/ChatBody/index.tsx | 9 +- web/screens/Chat/ChatItem/index.tsx | 26 ++ web/screens/Chat/EmptyChatScreen.tsx | 22 - web/screens/Chat/HistoryList/index.tsx | 117 ++++++ web/screens/Chat/SimpleTextMessage/index.tsx | 93 ++++ web/screens/Chat/index.tsx | 154 ++++++- .../ExploreModels/ExploreModelItem/index.tsx | 118 ++++++ .../ExploreModelItemHeader/index.tsx | 108 +++++ .../ExploreModels/ExploreModelList/index.tsx | 15 +- .../ExploreModels/ModelVersionItem/index.tsx | 96 +++++ .../ExploreModels}/ModelVersionList/index.tsx | 10 +- web/screens/ExploreModels/index.tsx | 31 +- web/screens/MyModels/BlankState/index.tsx | 77 ++++ web/screens/MyModels/index.tsx | 231 +++++++--- web/screens/Settings/Advanced/index.tsx | 34 +- .../{toggleAccent.tsx => TogglePrimary.tsx} | 38 +- .../{toggleTheme.tsx => ToggleTheme.tsx} | 23 +- web/screens/Settings/Appearance/index.tsx | 26 +- .../index.tsx} | 78 ++-- .../CorePlugins/PreferencePlugins/index.tsx | 111 +++-- web/screens/Settings/index.tsx | 177 ++++---- web/screens/Welcome/index.tsx | 33 +- web/services/cloudNativeService.ts | 69 ++- web/services/coreService.ts | 2 +- web/services/eventsService.ts | 2 + web/services/pluginService.ts | 4 +- web/styles/{ => base}/global.scss | 17 +- web/styles/{ => components}/code-block.scss | 1 + web/styles/components/loader.scss | 72 ++++ web/styles/{ => components}/message.scss | 1 + web/styles/loader.scss | 91 ---- web/styles/main.scss | 13 +- web/styles/variables.scss | 72 ---- web/tailwind.config.js | 110 +++-- web/tsconfig.json | 12 +- web/types/appearance.d.ts | 5 +- web/types/bot.d.ts | 32 -- web/types/chatMessage.d.ts | 1 + web/types/index.d.ts | 9 +- web/types/{users.ts => users.d.ts} | 4 +- web/uikit/button/index.tsx | 88 ---- web/uikit/icons/index.tsx | 13 - web/uikit/index.tsx | 4 - web/uikit/switch/index.tsx | 29 -- web/uikit/toggle/index.tsx | 45 -- web/utils/const.ts | 1 - web/utils/converter.ts | 7 +- web/utils/dummy.ts | 1 + web/utils/message.ts | 2 +- 267 files changed, 4404 insertions(+), 6488 deletions(-) create mode 100644 uikit/.prettierignore create mode 100644 uikit/.prettierrc create mode 100644 uikit/package.json create mode 100644 uikit/postcss.config.js create mode 100644 uikit/src/avatar/index.tsx create mode 100644 uikit/src/avatar/styles.scss create mode 100644 uikit/src/badge/index.tsx create mode 100644 uikit/src/badge/styles.scss create mode 100644 uikit/src/button/index.tsx create mode 100644 uikit/src/button/styles.scss create mode 100644 uikit/src/command/index.tsx create mode 100644 uikit/src/command/styles.scss create mode 100644 uikit/src/form/index.tsx create mode 100644 uikit/src/form/styles.scss create mode 100644 uikit/src/index.ts create mode 100644 uikit/src/input/index.tsx create mode 100644 uikit/src/input/styles.scss create mode 100644 uikit/src/main.scss create mode 100644 uikit/src/modal/index.tsx create mode 100644 uikit/src/modal/styles.scss create mode 100644 uikit/src/progress/index.tsx create mode 100644 uikit/src/progress/styles.scss create mode 100644 uikit/src/scroll-area/index.tsx create mode 100644 uikit/src/scroll-area/styles.scss create mode 100644 uikit/src/switch/index.tsx create mode 100644 uikit/src/switch/styles.scss create mode 100644 uikit/src/tooltip/index.tsx create mode 100644 uikit/src/tooltip/styles.scss create mode 100644 uikit/tailwind.config.js create mode 100644 uikit/tsconfig.json create mode 100644 uikit/types/declaration.d.ts create mode 100644 web/.eslintrc.js delete mode 100644 web/.eslintrc.json delete mode 100644 web/app/_components/ActiveModelTable/index.tsx delete mode 100644 web/app/_components/AvailableModelCard/index.tsx delete mode 100644 web/app/_components/Avatar/index.tsx delete mode 100644 web/app/_components/BasicPromptButton/index.tsx delete mode 100644 web/app/_components/BotInfo/index.tsx delete mode 100644 web/app/_components/BotInfoContainer/index.tsx delete mode 100644 web/app/_components/BotListContainer/index.tsx delete mode 100644 web/app/_components/BotListModal/index.tsx delete mode 100644 web/app/_components/BotPreview/index.tsx delete mode 100644 web/app/_components/BotSetting/index.tsx delete mode 100644 web/app/_components/CenterContainer/index.tsx delete mode 100644 web/app/_components/ChatBody/renderChatMessage.tsx delete mode 100644 web/app/_components/ChatItem/index.tsx delete mode 100644 web/app/_components/ConfirmDeleteModelModal/index.tsx delete mode 100644 web/app/_components/ConfirmSignOutModal/index.tsx delete mode 100644 web/app/_components/ConversationalCard/index.tsx delete mode 100644 web/app/_components/ConversationalList/index.tsx delete mode 100644 web/app/_components/CreateBotContainer/index.tsx delete mode 100644 web/app/_components/CreateBotInAdvance/index.tsx delete mode 100644 web/app/_components/CreateBotPromptInput/index.tsx delete mode 100644 web/app/_components/CustomBotTemperature/index.tsx delete mode 100644 web/app/_components/DownloadModelContent/index.tsx delete mode 100644 web/app/_components/DownloadModelTitle/index.tsx delete mode 100644 web/app/_components/DownloadedModelCard/index.tsx delete mode 100644 web/app/_components/DownloadedModelTable/index.tsx delete mode 100644 web/app/_components/DownloadingModelTable/index.tsx delete mode 100644 web/app/_components/DraggableProgressBar/index.tsx delete mode 100644 web/app/_components/DropdownBox/index.tsx delete mode 100644 web/app/_components/DropdownList/index.tsx delete mode 100644 web/app/_components/EmptyChatContainer/index.tsx delete mode 100644 web/app/_components/ExpandableHeader/index.tsx delete mode 100644 web/app/_components/ExploreModelContainer/index.tsx delete mode 100644 web/app/_components/ExploreModelFilter/index.tsx delete mode 100644 web/app/_components/ExploreModelItem/index.tsx delete mode 100644 web/app/_components/ExploreModelItemHeader/index.tsx delete mode 100644 web/app/_components/HamburgerButton/index.tsx delete mode 100644 web/app/_components/Header/index.tsx delete mode 100644 web/app/_components/HeaderBackButton/index.tsx delete mode 100644 web/app/_components/HeaderTitle/index.tsx delete mode 100644 web/app/_components/LeftContainer/index.tsx delete mode 100644 web/app/_components/LeftHeaderAction/index.tsx delete mode 100644 web/app/_components/LeftRibbonNav/index.tsx delete mode 100644 web/app/_components/LoginButton/index.tsx delete mode 100644 web/app/_components/MainChat/index.tsx delete mode 100644 web/app/_components/MainContainer/index.tsx delete mode 100644 web/app/_components/MainView/index.tsx delete mode 100644 web/app/_components/MenuHeader/index.tsx delete mode 100644 web/app/_components/MobileMenuPane/index.tsx delete mode 100644 web/app/_components/ModelActionButton/index.tsx delete mode 100644 web/app/_components/ModelActionMenu/index.tsx delete mode 100644 web/app/_components/ModelDownloadButton/index.tsx delete mode 100644 web/app/_components/ModelDownloadingButton/index.tsx delete mode 100644 web/app/_components/ModelDownloadingRow/index.tsx delete mode 100644 web/app/_components/ModelDownloadingTable/index.tsx delete mode 100644 web/app/_components/ModelInfoItem/index.tsx delete mode 100644 web/app/_components/ModelRow/index.tsx delete mode 100644 web/app/_components/ModelSearchBar/index.tsx delete mode 100644 web/app/_components/ModelSelector/index.tsx delete mode 100644 web/app/_components/ModelStatusComponent/index.tsx delete mode 100644 web/app/_components/ModelTable/index.tsx delete mode 100644 web/app/_components/ModelTableHeader/index.tsx delete mode 100644 web/app/_components/ModelVersionItem/index.tsx delete mode 100644 web/app/_components/MonitorBar/index.tsx delete mode 100644 web/app/_components/MyModelContainer/index.tsx delete mode 100644 web/app/_components/Preferences.tsx delete mode 100644 web/app/_components/PrimaryButton/index.tsx delete mode 100644 web/app/_components/ProgressSetting/index.tsx delete mode 100644 web/app/_components/RightContainer/index.tsx delete mode 100644 web/app/_components/SearchBar/index.tsx delete mode 100644 web/app/_components/SecondaryButton/index.tsx delete mode 100644 web/app/_components/SessionProviderWrapper.tsx delete mode 100644 web/app/_components/SidebarFooter/index.tsx delete mode 100644 web/app/_components/SidebarHeader/index.tsx delete mode 100644 web/app/_components/SidebarMenuItem/index.tsx delete mode 100644 web/app/_components/SimpleCheckbox/index.tsx delete mode 100644 web/app/_components/SimpleControlNetMessage.tsx delete mode 100644 web/app/_components/SimpleImageMessage/index.tsx delete mode 100644 web/app/_components/SimpleTag/TagStyleMapper.ts delete mode 100644 web/app/_components/SimpleTag/index.tsx delete mode 100644 web/app/_components/SimpleTextMessage/index.tsx delete mode 100644 web/app/_components/TextInputWithTitle/index.tsx delete mode 100644 web/app/_components/ToggleSwitch/index.tsx delete mode 100644 web/app/_components/UserProfileDropDown/index.tsx delete mode 100644 web/app/_components/ViewModelDetailButton/index.tsx delete mode 100644 web/app/_components/WelcomeContainer/index.tsx rename web/{app/_components => components}/BasicPromptAccessories/index.tsx (73%) rename web/{app/_components => components}/BasicPromptInput/index.tsx (86%) rename web/{app/_components => components}/ConfirmDeleteConversationModal/index.tsx (96%) rename web/{app/_components => components}/ConfirmationModal/index.tsx (97%) rename web/{app/_components => components}/HistoryItem/index.tsx (71%) rename web/{app/_components => components}/HistoryList/index.tsx (81%) rename web/{app/_components => components}/InputToolbar/index.tsx (68%) rename web/{app/_components => components}/LoadingIndicator.tsx (100%) rename web/{app/_components => components}/MainHeader/index.tsx (60%) rename web/{app/_components => components}/ModalNoActiveModel/index.tsx (89%) rename web/{app/_components => components}/ProgressBar/index.tsx (100%) rename web/{app/_components => components}/SendButton/index.tsx (56%) rename web/{app/_components => components}/SidebarEmptyHistory/index.tsx (68%) rename web/{app/_components => components}/SwitchingModelConfirmationModal/index.tsx (94%) rename web/{app/_components => components}/TextAreaWithTitle/index.tsx (78%) create mode 100644 web/constants/screens.ts rename web/{app/_components/SimpleTag/TagType.ts => constants/tagType.ts} (100%) delete mode 100644 web/containers/BottomBar/index.tsx create mode 100644 web/containers/Brand/Logo/Mark.tsx create mode 100644 web/containers/Layout/BottomBar/DownloadingState/index.tsx create mode 100644 web/containers/Layout/BottomBar/SystemItem/index.tsx create mode 100644 web/containers/Layout/BottomBar/index.tsx create mode 100644 web/containers/Layout/Ribbon/index.tsx create mode 100644 web/containers/Layout/TopBar/CommandListDownloadedModel/index.tsx create mode 100644 web/containers/Layout/TopBar/CommandSearch/index.tsx create mode 100644 web/containers/Layout/TopBar/index.tsx delete mode 100644 web/containers/Logo/CompactLogo/index.tsx create mode 100644 web/containers/ModalCancelDownload/index.tsx rename web/{helpers => containers/Providers}/EventHandler.tsx (80%) rename web/{helpers/EventListenerWrapper.tsx => containers/Providers/EventListener.tsx} (65%) rename web/{helpers/JotaiWrapper.tsx => containers/Providers/Jotai.tsx} (55%) rename web/{helpers/ThemeWrapper.tsx => containers/Providers/Theme.tsx} (64%) delete mode 100644 web/containers/Sidebar/Left.tsx delete mode 100644 web/containers/Sidebar/Right.tsx delete mode 100644 web/containers/Sidebar/index.tsx delete mode 100644 web/containers/SystemItem/index.tsx create mode 100644 web/containers/Toast/index.tsx delete mode 100644 web/containers/Topbar/index.tsx rename web/{helpers/FeatureToggleWrapper.tsx => context/FeatureToggle.tsx} (76%) delete mode 100644 web/helpers/atoms/Bot.atom.ts delete mode 100644 web/helpers/atoms/DownloadState.atom.ts delete mode 100644 web/helpers/atoms/DownloadedModel.atom.ts delete mode 100644 web/helpers/atoms/ExploreModelLoading.atom.ts delete mode 100644 web/helpers/atoms/MainView.atom.ts delete mode 100644 web/helpers/atoms/SideBarExpand.atom.ts delete mode 100644 web/helpers/withAnalytics.tsx create mode 100644 web/hooks/useActiveModel.ts create mode 100644 web/hooks/useBodyClass.ts delete mode 100644 web/hooks/useCreateBot.ts delete mode 100644 web/hooks/useDeleteBot.ts create mode 100644 web/hooks/useDownloadState.ts delete mode 100644 web/hooks/useGetBots.ts delete mode 100644 web/hooks/useGetCurrentUser.ts delete mode 100644 web/hooks/useGetHuggingFaceModel.ts create mode 100644 web/hooks/useMainViewState.ts delete mode 100644 web/hooks/useSignIn.ts delete mode 100644 web/hooks/useSignOut.ts delete mode 100644 web/hooks/useStartStopModel.ts delete mode 100644 web/hooks/useUpdateBot.ts delete mode 100644 web/models/User.ts create mode 100644 web/plugin/index.ts delete mode 100644 web/screens/Bot/index.tsx rename web/{app/_components => screens/Chat}/ChatBody/index.tsx (59%) create mode 100644 web/screens/Chat/ChatItem/index.tsx delete mode 100644 web/screens/Chat/EmptyChatScreen.tsx create mode 100644 web/screens/Chat/HistoryList/index.tsx create mode 100644 web/screens/Chat/SimpleTextMessage/index.tsx create mode 100644 web/screens/ExploreModels/ExploreModelItem/index.tsx create mode 100644 web/screens/ExploreModels/ExploreModelItemHeader/index.tsx create mode 100644 web/screens/ExploreModels/ModelVersionItem/index.tsx rename web/{app/_components => screens/ExploreModels}/ModelVersionList/index.tsx (82%) create mode 100644 web/screens/MyModels/BlankState/index.tsx rename web/screens/Settings/Appearance/{toggleAccent.tsx => TogglePrimary.tsx} (50%) rename web/screens/Settings/Appearance/{toggleTheme.tsx => ToggleTheme.tsx} (80%) rename web/screens/Settings/CorePlugins/{PluginsCatalog.tsx => PluginsCatalog/index.tsx} (78%) rename web/styles/{ => base}/global.scss (58%) rename web/styles/{ => components}/code-block.scss (98%) create mode 100644 web/styles/components/loader.scss rename web/styles/{ => components}/message.scss (70%) delete mode 100644 web/styles/loader.scss delete mode 100644 web/styles/variables.scss delete mode 100644 web/types/bot.d.ts rename web/types/{users.ts => users.d.ts} (78%) delete mode 100644 web/uikit/button/index.tsx delete mode 100644 web/uikit/icons/index.tsx delete mode 100644 web/uikit/index.tsx delete mode 100644 web/uikit/switch/index.tsx delete mode 100644 web/uikit/toggle/index.tsx delete mode 100644 web/utils/const.ts diff --git a/.github/workflows/jan-electron-linter-and-test.yml b/.github/workflows/jan-electron-linter-and-test.yml index 69552f17e9..90802baf77 100644 --- a/.github/workflows/jan-electron-linter-and-test.yml +++ b/.github/workflows/jan-electron-linter-and-test.yml @@ -4,29 +4,31 @@ on: branches: - main paths: - - 'electron/**' + - "electron/**" - .github/workflows/jan-electron-linter-and-test.yml - - 'web/**' - - 'package.json' - - 'node_modules/**' - - 'yarn.lock' + - "web/**" + - "uikit/**" + - "package.json" + - "node_modules/**" + - "yarn.lock" pull_request: branches: - main paths: - - 'electron/**' + - "electron/**" - .github/workflows/linter-and-test.yml - - 'web/**' - - 'package.json' - - 'node_modules/**' - - 'yarn.lock' + - "web/**" + - "uikit/**" + - "package.json" + - "node_modules/**" + - "yarn.lock" jobs: test-on-macos: runs-on: [self-hosted, macOS, macos-desktop] steps: - - name: 'Cleanup build folder' + - name: "Cleanup build folder" run: | ls -la ./ rm -rf ./* || true @@ -41,6 +43,12 @@ jobs: with: node-version: 20 + - name: Build uikit + run: | + cd uikit + yarn install + yarn build + - name: Linter and test run: | yarn config set network-timeout 300000 @@ -73,6 +81,12 @@ jobs: with: node-version: 20 + - name: Build uikit + run: | + cd uikit + yarn install + yarn build + - name: Linter and test run: | yarn config set network-timeout 300000 @@ -85,7 +99,7 @@ jobs: test-on-ubuntu: runs-on: [self-hosted, Linux, ubuntu-desktop] steps: - - name: 'Cleanup build folder' + - name: "Cleanup build folder" run: | ls -la ./ rm -rf ./* || true @@ -100,6 +114,12 @@ jobs: with: node-version: 20 + - name: Build uikit + run: | + cd uikit + yarn install + yarn build + - name: Linter and test run: | export DISPLAY=$(w -h | awk 'NR==1 {print $2}') @@ -109,4 +129,4 @@ jobs: yarn install yarn build:plugins yarn build:test-linux - yarn test \ No newline at end of file + yarn test diff --git a/electron/main.ts b/electron/main.ts index 8e175a62d0..cecc90f42a 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -53,11 +53,12 @@ app.on("quit", () => { function createMainWindow() { mainWindow = new BrowserWindow({ width: 1200, + minWidth: 800, height: 800, show: false, trafficLightPosition: { - x: 16, - y: 10, + x: 10, + y: 15, }, titleBarStyle: "hidden", vibrancy: "sidebar", diff --git a/electron/tests/explore.e2e.spec.ts b/electron/tests/explore.e2e.spec.ts index 6df823fc1e..5a4412cb3a 100644 --- a/electron/tests/explore.e2e.spec.ts +++ b/electron/tests/explore.e2e.spec.ts @@ -36,12 +36,6 @@ test.afterAll(async () => { test("explores models", async () => { await page.getByTestId("Explore Models").first().click(); - const header = await page - .getByRole("heading") - .filter({ hasText: "Explore Models" }) - .first() - .isDisabled(); - expect(header).toBe(false); - + await page.getByTestId("testid-explore-models").isVisible(); // More test cases here... }); diff --git a/electron/tests/my-models.e2e.spec.ts b/electron/tests/my-models.e2e.spec.ts index 788b80fc07..a3355fb335 100644 --- a/electron/tests/my-models.e2e.spec.ts +++ b/electron/tests/my-models.e2e.spec.ts @@ -36,6 +36,6 @@ test.afterAll(async () => { test("shows my models", async () => { await page.getByTestId("My Models").first().click(); - await page.getByTestId("testid-mymodels-header").isVisible(); + await page.getByTestId("testid-my-models").isVisible(); // More test cases here... }); diff --git a/package.json b/package.json index 2a489d9a06..7356a0fd51 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,17 @@ "private": true, "workspaces": { "packages": [ + "uikit", + "core", "electron", "web", "server" ], "nohoist": [ + "uikit", + "uikit/*", + "core", + "core/*", "electron", "electron/**", "web", @@ -23,13 +29,15 @@ "dev:web": "yarn workspace jan-web dev", "dev": "concurrently --kill-others \"yarn dev:web\" \"wait-on http://localhost:3000 && yarn dev:electron\"", "test-local": "yarn lint && yarn build:test && yarn test", + "dev:uikit": "yarn workspace @janhq/uikit install && yarn workspace @janhq/uikit dev", + "build:uikit": "yarn workspace @janhq/uikit install && yarn workspace @janhq/uikit build", "build:core": "cd core && yarn install && yarn run build", "build:web": "yarn workspace jan-web build && cpx \"web/out/**\" \"electron/renderer/\"", "build:electron": "yarn workspace jan build", "build:electron:test": "yarn workspace jan build:test", "build:pull-plugins": "rimraf ./electron/core/pre-install/*.tgz && cd ./electron/core/pre-install && npm pack @janhq/inference-plugin @janhq/monitoring-plugin", - "build:plugins": "rimraf ./electron/core/pre-install/*.tgz && concurrently --kill-others-on-fail \"cd ./plugins/conversational-plugin && npm install && npm run postinstall && npm run build:publish\" \"cd ./plugins/inference-plugin && npm install --ignore-scripts && npm run postinstall:dev && npm run build:publish\" \"cd ./plugins/model-plugin && npm install && npm run postinstall && npm run build:publish\" \"cd ./plugins/monitoring-plugin && npm install && npm run postinstall && npm run build:publish\"", - "build:plugins-web": "rimraf ./electron/core/pre-install/*.tgz && concurrently --kill-others-on-fail \"cd ./plugins/conversational-plugin && npm install && npm run build:deps && npm run postinstall\" \"cd ./plugins/inference-plugin && npm install && npm run postinstall\" \"cd ./plugins/model-plugin && npm install && npm run postinstall\" \"cd ./plugins/monitoring-plugin && npm install && npm run postinstall\" && concurrently --kill-others-on-fail \"cd ./plugins/conversational-plugin && npm run build:publish\" \"cd ./plugins/inference-plugin && npm run build:publish\" \"cd ./plugins/model-plugin && npm run build:publish\" \"cd ./plugins/monitoring-plugin && npm run build:publish\"", + "build:plugins": "rimraf ./electron/core/pre-install/*.tgz && concurrently --kill-others-on-fail \"cd ./plugins/conversational-json && npm install && npm run postinstall && npm run build:publish\" \"cd ./plugins/inference-plugin && npm install --ignore-scripts && npm run postinstall:dev && npm run build:publish\" \"cd ./plugins/model-plugin && npm install && npm run postinstall && npm run build:publish\" \"cd ./plugins/monitoring-plugin && npm install && npm run postinstall && npm run build:publish\"", + "build:plugins-web": "rimraf ./electron/core/pre-install/*.tgz && concurrently --kill-others-on-fail \"cd ./plugins/conversational-json && npm install && npm run build:deps && npm run postinstall\" \"cd ./plugins/inference-plugin && npm install && npm run postinstall\" \"cd ./plugins/model-plugin && npm install && npm run postinstall\" \"cd ./plugins/monitoring-plugin && npm install && npm run postinstall\" && concurrently --kill-others-on-fail \"cd ./plugins/conversational-json && npm run build:publish\" \"cd ./plugins/inference-plugin && npm run build:publish\" \"cd ./plugins/model-plugin && npm run build:publish\" \"cd ./plugins/monitoring-plugin && npm run build:publish\"", "build": "yarn build:web && yarn build:electron", "build:test": "yarn build:web && yarn build:electron:test", "build:test-darwin": "yarn build:web && yarn workspace jan build:test-darwin", @@ -42,7 +50,7 @@ "build:publish-darwin": "yarn build:web && yarn workspace jan build:publish-darwin", "build:publish-win32": "yarn build:web && yarn workspace jan build:publish-win32", "build:publish-linux": "yarn build:web && yarn workspace jan build:publish-linux", - "build:web-plugins": "yarn build:web && yarn build:plugins-web && mkdir -p \"./web/out/plugins/conversational-plugin\" && cp \"./plugins/conversational-plugin/dist/index.js\" \"./web/out/plugins/conversational-plugin\" && mkdir -p \"./web/out/plugins/inference-plugin\" && cp \"./plugins/inference-plugin/dist/index.js\" \"./web/out/plugins/inference-plugin\" && mkdir -p \"./web/out/plugins/model-plugin\" && cp \"./plugins/model-plugin/dist/index.js\" \"./web/out/plugins/model-plugin\" && mkdir -p \"./web/out/plugins/monitoring-plugin\" && cp \"./plugins/monitoring-plugin/dist/index.js\" \"./web/out/plugins/monitoring-plugin\"", + "build:web-plugins": "yarn build:web && yarn build:plugins-web && mkdir -p \"./web/out/plugins/conversational-json\" && cp \"./plugins/conversational-json/dist/index.js\" \"./web/out/plugins/conversational-json\" && mkdir -p \"./web/out/plugins/inference-plugin\" && cp \"./plugins/inference-plugin/dist/index.js\" \"./web/out/plugins/inference-plugin\" && mkdir -p \"./web/out/plugins/model-plugin\" && cp \"./plugins/model-plugin/dist/index.js\" \"./web/out/plugins/model-plugin\" && mkdir -p \"./web/out/plugins/monitoring-plugin\" && cp \"./plugins/monitoring-plugin/dist/index.js\" \"./web/out/plugins/monitoring-plugin\"", "server:prod": "yarn workspace server build && yarn build:web-plugins && cpx \"web/out/**\" \"server/build/renderer/\" && mkdir -p ./server/build/@janhq && cp -r ./plugins/* ./server/build/@janhq", "start:server": "yarn server:prod && node server/build/main.js" }, @@ -52,8 +60,5 @@ "rimraf": "^3.0.2", "wait-on": "^7.0.1" }, - "version": "0.0.0", - "dependencies": { - "@janhq/core": "file:core" - } + "version": "0.0.0" } diff --git a/uikit/.prettierignore b/uikit/.prettierignore new file mode 100644 index 0000000000..02d9145c14 --- /dev/null +++ b/uikit/.prettierignore @@ -0,0 +1,5 @@ +.next/ +node_modules/ +dist/ +*.hbs +*.mdx \ No newline at end of file diff --git a/uikit/.prettierrc b/uikit/.prettierrc new file mode 100644 index 0000000000..933d88d621 --- /dev/null +++ b/uikit/.prettierrc @@ -0,0 +1,8 @@ +{ + "semi": false, + "singleQuote": true, + "quoteProps": "consistent", + "trailingComma": "es5", + "endOfLine": "lf", + "plugins": ["prettier-plugin-tailwindcss"] +} diff --git a/uikit/package.json b/uikit/package.json new file mode 100644 index 0000000000..dd67be5992 --- /dev/null +++ b/uikit/package.json @@ -0,0 +1,53 @@ +{ + "name": "@janhq/uikit", + "version": "0.1.0", + "license": "MIT", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "files": [ + "dist/**" + ], + "scripts": { + "build:styles": "postcss src/main.scss -o dist/index.css --use postcss-import", + "build:react": "tsup src/index.{ts,tsx} --format cjs,esm --dts --external react react-dom --minify terser --splitting --sourcemap", + "dev:react": "tsup src/index.{ts,tsx} --format cjs,esm --watch --dts", + "dev:styles": "postcss src/main.scss -o dist/index.css -u postcss-import -w", + "build": "yarn build:styles && yarn build:react", + "dev": "concurrently --kill-others \"yarn dev:styles\" \"yarn dev:react\"" + }, + "dependencies": { + "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-context": "^1.0.1", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-progress": "^1.0.3", + "@radix-ui/react-scroll-area": "^1.0.5", + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-switch": "^1.0.3", + "@radix-ui/react-toast": "^1.1.5", + "@radix-ui/react-tooltip": "^1.0.7", + "autoprefixer": "^10.4.16", + "class-variance-authority": "^0.7.0", + "cmdk": "^0.2.0", + "lucide-react": "^0.292.0", + "postcss": "^8.4.31", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-hook-form": "^7.47.0", + "scss": "^0.2.4", + "tailwindcss": "^3.3.5" + }, + "devDependencies": { + "concurrently": "^8.2.2", + "postcss-cli": "^10.1.0", + "postcss-import": "^15.1.0", + "prejss-cli": "^0.3.3", + "prettier": "^3.0.3", + "prettier-plugin-tailwindcss": "^0.5.6", + "tailwind-merge": "^2.0.0", + "terser": "^5.24.0", + "tsup": "^7.2.0", + "typescript": "^5.2.2" + } +} diff --git a/uikit/postcss.config.js b/uikit/postcss.config.js new file mode 100644 index 0000000000..a65a35628e --- /dev/null +++ b/uikit/postcss.config.js @@ -0,0 +1,8 @@ +module.exports = { + plugins: { + "tailwindcss/nesting": {}, + tailwindcss: {}, + autoprefixer: {}, + "postcss-import": {}, + }, +}; diff --git a/uikit/src/avatar/index.tsx b/uikit/src/avatar/index.tsx new file mode 100644 index 0000000000..bdacbba4a6 --- /dev/null +++ b/uikit/src/avatar/index.tsx @@ -0,0 +1,43 @@ +'use client' + +import { forwardRef, ElementRef, ComponentPropsWithoutRef } from 'react' +import * as AvatarPrimitive from '@radix-ui/react-avatar' +import { twMerge } from 'tailwind-merge' + +const Avatar = forwardRef< + ElementRef, + ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Avatar.displayName = AvatarPrimitive.Root.displayName + +const AvatarImage = forwardRef< + ElementRef, + ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarImage.displayName = AvatarPrimitive.Image.displayName + +const AvatarFallback = forwardRef< + ElementRef, + ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/uikit/src/avatar/styles.scss b/uikit/src/avatar/styles.scss new file mode 100644 index 0000000000..dacae26b5e --- /dev/null +++ b/uikit/src/avatar/styles.scss @@ -0,0 +1,11 @@ +.avatar { + @apply relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full; + + &-image { + @apply aspect-square h-full w-full; + } + + &-fallback { + @apply bg-muted flex h-full w-full items-center justify-center rounded-full font-bold uppercase; + } +} diff --git a/uikit/src/badge/index.tsx b/uikit/src/badge/index.tsx new file mode 100644 index 0000000000..a2eeaac2d5 --- /dev/null +++ b/uikit/src/badge/index.tsx @@ -0,0 +1,30 @@ +import * as React from 'react' +import { cva, type VariantProps } from 'class-variance-authority' +import { twMerge } from 'tailwind-merge' + +const badgeVariants = cva('badge', { + variants: { + themes: { + primary: 'badge-primary', + success: 'badge-success', + secondary: 'badge-secondary', + danger: 'badge-danger', + outline: 'badge-outline', + }, + }, + defaultVariants: { + themes: 'primary', + }, +}) + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, themes, ...props }: BadgeProps) { + return ( +
+ ) +} + +export { Badge, badgeVariants } diff --git a/uikit/src/badge/styles.scss b/uikit/src/badge/styles.scss new file mode 100644 index 0000000000..e5a783d88d --- /dev/null +++ b/uikit/src/badge/styles.scss @@ -0,0 +1,23 @@ +.badge { + @apply focus:ring-ring border-border inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2; + + &-primary { + @apply bg-primary text-primary-foreground hover:bg-primary/80 border-transparent; + } + + &-success { + @apply border-transparent bg-green-500 text-green-900 hover:bg-green-500/80; + } + + &-secondary { + @apply bg-secondary text-secondary-foreground hover:bg-secondary/80; + } + + &-danger { + @apply bg-danger text-danger-foreground hover:bg-danger/80 border-transparent; + } + + &-outline { + @apply text-foreground border-border border; + } +} diff --git a/uikit/src/button/index.tsx b/uikit/src/button/index.tsx new file mode 100644 index 0000000000..943e2bc344 --- /dev/null +++ b/uikit/src/button/index.tsx @@ -0,0 +1,98 @@ +'use client' + +import { forwardRef, ButtonHTMLAttributes } from 'react' +import { Slot } from '@radix-ui/react-slot' +import { cva, type VariantProps } from 'class-variance-authority' + +import { twMerge } from 'tailwind-merge' + +const buttonVariants = cva('btn', { + variants: { + themes: { + primary: 'btn-primary', + danger: 'btn-danger', + outline: 'btn-outline', + secondary: 'btn-secondary', + ghost: 'btn-ghost', + }, + size: { + sm: 'btn-sm', + md: 'btn-md', + lg: 'btn-lg', + }, + block: { + true: 'w-full', + }, + loading: { + true: 'btn-loading', + }, + }, + defaultVariants: { + themes: 'primary', + size: 'md', + }, +}) + +export interface ButtonProps + extends ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = forwardRef( + ( + { + className, + themes, + size, + block, + loading, + asChild = false, + children, + ...props + }, + ref + ) => { + const Comp = asChild ? Slot : 'button' + return ( + + {loading ? ( + <> + + {children} + + ) : ( + children + )} + + ) + } +) +Button.displayName = 'Button' + +export { Button, buttonVariants } diff --git a/uikit/src/button/styles.scss b/uikit/src/button/styles.scss new file mode 100644 index 0000000000..08b59537f3 --- /dev/null +++ b/uikit/src/button/styles.scss @@ -0,0 +1,64 @@ +.btn { + @apply inline-flex items-center justify-center whitespace-nowrap rounded-md font-semibold transition-colors; + @apply focus-visible:ring-ring cursor-pointer focus-visible:outline-none focus-visible:ring-1; + @apply disabled:pointer-events-none disabled:opacity-50; + + &-primary { + @apply bg-primary hover:bg-primary/90 text-white; + } + + &-danger { + @apply bg-danger text-danger-foreground hover:bg-danger/90; + } + + &-outline { + @apply border-input hover:bg-accent hover:text-accent-foreground border bg-transparent; + } + + &-secondary { + @apply bg-secondary text-secondary-foreground hover:bg-secondary/80; + } + + &-ghost { + @apply hover:bg-accent hover:text-accent-foreground; + } + + &-sm { + @apply h-7 rounded-md px-3 text-xs; + } + + &-md { + @apply h-9 px-4 py-2; + } + + &-lg { + @apply h-10 rounded-md px-8; + } + + &-loading { + @apply pointer-events-none opacity-50; + &-circle { + @apply mr-2 h-4 animate-spin opacity-50; + > circle { + opacity: 0.25; + } + > path { + opacity: 0.75; + } + } + } +} + +[type='button'], +[type='reset'], +[type='submit'] { + &.btn-primary { + @apply bg-primary hover:bg-primary/90; + } + &.btn-secondary { + @apply bg-secondary hover:bg-secondary/80; + } + &.btn-danger { + @apply bg-danger hover:bg-danger/90; + } +} diff --git a/uikit/src/command/index.tsx b/uikit/src/command/index.tsx new file mode 100644 index 0000000000..0d87d72c92 --- /dev/null +++ b/uikit/src/command/index.tsx @@ -0,0 +1,132 @@ +'use client' + +import * as React from 'react' +import { DialogProps } from '@radix-ui/react-dialog' +import { Command as CommandPrimitive } from 'cmdk' +import { Search } from 'lucide-react' + +import { Modal, ModalContent } from '../modal' + +import { twMerge } from 'tailwind-merge' + +const Command = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Command.displayName = CommandPrimitive.displayName + +interface CommandModalProps extends DialogProps {} + +const CommandModal = ({ children, ...props }: CommandModalProps) => { + return ( + + + + {children} + + + + ) +} + +const CommandInput = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( +
+ + +
+)) + +CommandInput.displayName = CommandPrimitive.Input.displayName + +const CommandList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandList.displayName = CommandPrimitive.List.displayName + +const CommandEmpty = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)) + +CommandEmpty.displayName = CommandPrimitive.Empty.displayName + +const CommandGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandGroup.displayName = CommandPrimitive.Group.displayName + +const CommandSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +CommandSeparator.displayName = CommandPrimitive.Separator.displayName + +const CommandItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandItem.displayName = CommandPrimitive.Item.displayName + +const CommandShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return +} +CommandShortcut.displayName = 'CommandShortcut' + +export { + Command, + CommandModal, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +} diff --git a/uikit/src/command/styles.scss b/uikit/src/command/styles.scss new file mode 100644 index 0000000000..cbcbbf4d6a --- /dev/null +++ b/uikit/src/command/styles.scss @@ -0,0 +1,45 @@ +.command { + @apply bg-background/80 text-muted-foreground flex h-full w-full flex-col overflow-hidden rounded-md text-left; + + &-modal-content { + @apply overflow-hidden p-0; + > .modal-close { + top: 12px; + } + } + + &-input-wrapper { + @apply border-border flex items-center border-b px-3; + } + + &-input { + @apply placeholder:text-muted-foreground flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none disabled:cursor-not-allowed disabled:opacity-50; + } + + &-search-icon { + @apply mr-2 h-4 w-4 shrink-0 opacity-50; + } + + &-list { + @apply max-h-[300px] overflow-y-auto overflow-x-hidden py-2; + } + + &-list-item { + @apply text-foreground aria-selected:bg-accent relative flex cursor-pointer select-none items-center rounded-md px-2 py-2 text-sm outline-none; + } + + &-empty { + @apply py-6 text-center text-sm; + } + + &-group { + @apply text-muted-foreground overflow-hidden p-1 px-2 py-1.5 text-xs font-medium; + > [cmdk-group-heading] { + @apply mb-2 pl-2; + } + } + + &-sc { + @apply text-muted-foreground ml-auto text-xs tracking-widest; + } +} diff --git a/uikit/src/form/index.tsx b/uikit/src/form/index.tsx new file mode 100644 index 0000000000..1a4abdb6d4 --- /dev/null +++ b/uikit/src/form/index.tsx @@ -0,0 +1,175 @@ +import * as React from 'react' +import * as LabelPrimitive from '@radix-ui/react-label' +import { Slot } from '@radix-ui/react-slot' +import { + Controller, + ControllerProps, + FieldPath, + FieldValues, + FormProvider, + useFormContext, +} from 'react-hook-form' +import { twMerge } from 'tailwind-merge' + +const Form = FormProvider + +type FormFieldContextValue< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath, +> = { + name: TName +} + +const FormFieldContext = React.createContext( + {} as FormFieldContextValue +) + +const FormField = < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath, +>({ + ...props +}: ControllerProps) => { + return ( + + + + ) +} + +const useFormField = () => { + const fieldContext = React.useContext(FormFieldContext) + const itemContext = React.useContext(FormItemContext) + const { getFieldState, formState } = useFormContext() + + const fieldState = getFieldState(fieldContext.name, formState) + + if (!fieldContext) { + throw new Error('useFormField should be used within ') + } + + const { id } = itemContext + + return { + id, + name: fieldContext.name, + formItemId: `${id}-form-item`, + formDescriptionId: `${id}-form-item-description`, + formMessageId: `${id}-form-item-message`, + ...fieldState, + } +} + +type FormItemContextValue = { + id: string +} + +const FormItemContext = React.createContext( + {} as FormItemContextValue +) + +const FormItem = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => { + const id = React.useId() + + return ( + +
+ + ) +}) +FormItem.displayName = 'FormItem' + +const FormLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + const { error, formItemId } = useFormField() + + return ( +