index.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import type { FC } from 'react'
  2. import { useState } from 'react'
  3. import type {
  4. DefaultModel,
  5. Model,
  6. ModelItem,
  7. } from '../declarations'
  8. import { useCurrentProviderAndModel } from '../hooks'
  9. import ModelTrigger from './model-trigger'
  10. import EmptyTrigger from './empty-trigger'
  11. import DeprecatedModelTrigger from './deprecated-model-trigger'
  12. import Popup from './popup'
  13. import {
  14. PortalToFollowElem,
  15. PortalToFollowElemContent,
  16. PortalToFollowElemTrigger,
  17. } from '@/app/components/base/portal-to-follow-elem'
  18. type ModelSelectorProps = {
  19. defaultModel?: DefaultModel
  20. modelList: Model[]
  21. triggerClassName?: string
  22. popupClassName?: string
  23. onSelect?: (model: DefaultModel) => void
  24. readonly?: boolean
  25. }
  26. const ModelSelector: FC<ModelSelectorProps> = ({
  27. defaultModel,
  28. modelList,
  29. triggerClassName,
  30. popupClassName,
  31. onSelect,
  32. readonly,
  33. }) => {
  34. const [open, setOpen] = useState(false)
  35. const {
  36. currentProvider,
  37. currentModel,
  38. } = useCurrentProviderAndModel(
  39. modelList,
  40. defaultModel,
  41. )
  42. const handleSelect = (provider: string, model: ModelItem) => {
  43. setOpen(false)
  44. if (onSelect)
  45. onSelect({ provider, model: model.model })
  46. }
  47. const handleToggle = () => {
  48. if (readonly)
  49. return
  50. setOpen(v => !v)
  51. }
  52. return (
  53. <PortalToFollowElem
  54. open={open}
  55. onOpenChange={setOpen}
  56. placement='bottom-start'
  57. offset={4}
  58. >
  59. <div className='relative'>
  60. <PortalToFollowElemTrigger
  61. onClick={handleToggle}
  62. className='block'
  63. >
  64. {
  65. currentModel && currentProvider && (
  66. <ModelTrigger
  67. open={open}
  68. provider={currentProvider}
  69. model={currentModel}
  70. className={triggerClassName}
  71. readonly={readonly}
  72. />
  73. )
  74. }
  75. {
  76. !currentModel && defaultModel && (
  77. <DeprecatedModelTrigger
  78. modelName={defaultModel?.model || ''}
  79. providerName={defaultModel?.provider || ''}
  80. className={triggerClassName}
  81. />
  82. )
  83. }
  84. {
  85. !defaultModel && (
  86. <EmptyTrigger
  87. open={open}
  88. className={triggerClassName}
  89. />
  90. )
  91. }
  92. </PortalToFollowElemTrigger>
  93. <PortalToFollowElemContent className={`z-[1002] ${popupClassName}`}>
  94. <Popup
  95. defaultModel={defaultModel}
  96. modelList={modelList}
  97. onSelect={handleSelect}
  98. />
  99. </PortalToFollowElemContent>
  100. </div>
  101. </PortalToFollowElem>
  102. )
  103. }
  104. export default ModelSelector