CreateNotebookDrawer.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import React, { useState } from 'react'
  2. import { Plus, ChevronRight } from 'lucide-react'
  3. import { CreateGroupData } from '../types'
  4. import { useLanguage } from '../contexts/LanguageContext'
  5. import { useToast } from '../contexts/ToastContext'
  6. interface CreateNotebookDrawerProps {
  7. isOpen: boolean
  8. onClose: () => void
  9. onCreate: (data: CreateGroupData) => Promise<void>
  10. }
  11. export const CreateNotebookDrawer: React.FC<CreateNotebookDrawerProps> = ({
  12. isOpen,
  13. onClose,
  14. onCreate,
  15. }) => {
  16. const { t } = useLanguage()
  17. const { showError } = useToast()
  18. const [name, setName] = useState('')
  19. const [description, setDescription] = useState('')
  20. const [isSubmitting, setIsSubmitting] = useState(false)
  21. const handleSubmit = async (e: React.FormEvent) => {
  22. e.preventDefault()
  23. if (!name.trim()) return
  24. try {
  25. setIsSubmitting(true)
  26. await onCreate({
  27. name: name.trim(),
  28. description: description.trim(),
  29. color: '#3b82f6', // Default color
  30. })
  31. // Reset form
  32. setName('')
  33. setDescription('')
  34. onClose()
  35. } catch (error) {
  36. console.error('Failed to create notebook:', error)
  37. showError(t('createFailedRetry'))
  38. } finally {
  39. setIsSubmitting(false)
  40. }
  41. }
  42. return (
  43. <>
  44. {/* Backdrop */}
  45. {isOpen && (
  46. <div
  47. className="fixed inset-0 bg-black/20 backdrop-blur-sm z-40 transition-opacity duration-300"
  48. onClick={onClose}
  49. />
  50. )}
  51. {/* Drawer */}
  52. <div
  53. className={`fixed right-0 top-0 h-full w-full max-w-md bg-white shadow-2xl z-50 transform transition-transform duration-300 ease-out ${isOpen ? 'translate-x-0' : 'translate-x-full'
  54. }`}
  55. >
  56. <div className="flex flex-col h-full">
  57. {/* Header */}
  58. <div className="flex items-center justify-between px-6 py-4 border-b bg-slate-50">
  59. <h2 className="text-xl font-semibold text-slate-800 flex items-center gap-2">
  60. <Plus className="w-6 h-6 text-blue-600" />
  61. {t('createNotebookTitle')}
  62. </h2>
  63. <button
  64. onClick={onClose}
  65. className="p-2 text-slate-400 hover:text-slate-600 hover:bg-slate-200 rounded-full transition-colors"
  66. >
  67. <ChevronRight size={24} />
  68. </button>
  69. </div>
  70. {/* Content */}
  71. <div className="flex-1 overflow-y-auto p-6">
  72. <form id="create-notebook-form" onSubmit={handleSubmit} className="space-y-6">
  73. <div>
  74. <label className="block text-sm font-medium text-slate-700 mb-1">
  75. {t('name')} <span className="text-red-500">*</span>
  76. </label>
  77. <input
  78. type="text"
  79. value={name}
  80. onChange={(e) => setName(e.target.value)}
  81. className="w-full px-4 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500 bg-slate-50"
  82. placeholder={t('namePlaceholder')}
  83. required
  84. autoFocus
  85. />
  86. <p className="mt-1 text-xs text-slate-500">{t('nameHelp')}</p>
  87. </div>
  88. <div>
  89. <label className="block text-sm font-medium text-slate-700 mb-1">
  90. {t('shortDescription')}
  91. </label>
  92. <input
  93. type="text"
  94. value={description}
  95. onChange={(e) => setDescription(e.target.value)}
  96. className="w-full px-4 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500 bg-slate-50"
  97. placeholder={t('descPlaceholder')}
  98. />
  99. </div>
  100. </form>
  101. </div>
  102. {/* Footer */}
  103. <div className="p-6 border-t bg-slate-50">
  104. <button
  105. type="submit"
  106. form="create-notebook-form"
  107. disabled={isSubmitting || !name.trim()}
  108. className="w-full flex items-center justify-center gap-2 px-6 py-3 bg-blue-600 text-white font-medium rounded-xl hover:bg-blue-700 active:scale-[0.98] transition-all disabled:opacity-50 disabled:cursor-not-allowed shadow-lg shadow-blue-600/20"
  109. >
  110. <Plus size={20} />
  111. {isSubmitting ? t('creating') : t('createNow')}
  112. </button>
  113. </div>
  114. </div>
  115. </div>
  116. </>
  117. )
  118. }