You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import type { SlashCommandHandler } from './types'
  2. import type { CommandSearchResult } from '../types'
  3. import type { ReactNode } from 'react'
  4. import React from 'react'
  5. import { RiComputerLine, RiMoonLine, RiSunLine } from '@remixicon/react'
  6. import i18n from '@/i18n-config/i18next-config'
  7. import { registerCommands, unregisterCommands } from './command-bus'
  8. // Theme dependency types
  9. type ThemeDeps = {
  10. setTheme?: (value: 'light' | 'dark' | 'system') => void
  11. }
  12. const THEME_ITEMS: { id: 'light' | 'dark' | 'system'; titleKey: string; descKey: string; icon: ReactNode }[] = [
  13. {
  14. id: 'system',
  15. titleKey: 'app.gotoAnything.actions.themeSystem',
  16. descKey: 'app.gotoAnything.actions.themeSystemDesc',
  17. icon: <RiComputerLine className='h-4 w-4 text-text-tertiary' />,
  18. },
  19. {
  20. id: 'light',
  21. titleKey: 'app.gotoAnything.actions.themeLight',
  22. descKey: 'app.gotoAnything.actions.themeLightDesc',
  23. icon: <RiSunLine className='h-4 w-4 text-text-tertiary' />,
  24. },
  25. {
  26. id: 'dark',
  27. titleKey: 'app.gotoAnything.actions.themeDark',
  28. descKey: 'app.gotoAnything.actions.themeDarkDesc',
  29. icon: <RiMoonLine className='h-4 w-4 text-text-tertiary' />,
  30. },
  31. ]
  32. const buildThemeCommands = (query: string, locale?: string): CommandSearchResult[] => {
  33. const q = query.toLowerCase()
  34. const list = THEME_ITEMS.filter(item =>
  35. !q
  36. || i18n.t(item.titleKey, { lng: locale }).toLowerCase().includes(q)
  37. || item.id.includes(q),
  38. )
  39. return list.map(item => ({
  40. id: item.id,
  41. title: i18n.t(item.titleKey, { lng: locale }),
  42. description: i18n.t(item.descKey, { lng: locale }),
  43. type: 'command' as const,
  44. icon: (
  45. <div className='flex h-6 w-6 items-center justify-center rounded-md border-[0.5px] border-divider-regular bg-components-panel-bg'>
  46. {item.icon}
  47. </div>
  48. ),
  49. data: { command: 'theme.set', args: { value: item.id } },
  50. }))
  51. }
  52. /**
  53. * Theme command handler
  54. * Integrates UI building, search, and registration logic
  55. */
  56. export const themeCommand: SlashCommandHandler<ThemeDeps> = {
  57. name: 'theme',
  58. description: 'Switch between light and dark themes',
  59. mode: 'submenu', // Explicitly set submenu mode
  60. async search(args: string, locale: string = 'en') {
  61. // Return theme options directly, regardless of parameters
  62. return buildThemeCommands(args, locale)
  63. },
  64. register(deps: ThemeDeps) {
  65. registerCommands({
  66. 'theme.set': async (args) => {
  67. deps.setTheme?.(args?.value)
  68. },
  69. })
  70. },
  71. unregister() {
  72. unregisterCommands(['theme.set'])
  73. },
  74. }