Advertisement
nikitodeon123

Untitled

Apr 23rd, 2025
19
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.28 KB | None | 0 0
  1. night-light-provider.tsx
  2. 'use client'
  3.  
  4. import { createContext, useContext, useEffect, useState } from 'react'
  5.  
  6. type NightLightContextType = {
  7. enabled: boolean
  8. strength: number // 0-100 scale
  9. toggle: () => void
  10. setStrength: (value: number) => void
  11. }
  12.  
  13. const NightLightContext = createContext<NightLightContextType | undefined>(
  14. undefined
  15. )
  16.  
  17. export function NightLightProvider({
  18. children
  19. }: {
  20. children: React.ReactNode
  21. }) {
  22. const [enabled, setEnabled] = useState(false)
  23. const [strength, setStrength] = useState(50)
  24.  
  25. const toggle = () => setEnabled(prev => !prev)
  26.  
  27. useEffect(() => {
  28. const styleId = 'night-light-style'
  29. let styleElement = document.getElementById(
  30. styleId
  31. ) as HTMLStyleElement | null
  32.  
  33. if (!styleElement) {
  34. styleElement = document.createElement('style')
  35. styleElement.id = styleId
  36. document.head.appendChild(styleElement)
  37. }
  38.  
  39. if (enabled) {
  40. // Усиливаем эффект: 85% -> 55% Windows (коэффициент ~1.55)
  41. const enhancedOpacity = (strength / 100) * 0.93 // было 0.6, стало 0.93
  42. const color = `rgba(255, 159, 46, ${enhancedOpacity})`
  43.  
  44. styleElement.textContent = `
  45. html::after {
  46. content: '';
  47. position: fixed;
  48. top: 0;
  49. left: 0;
  50. right: 0;
  51. bottom: 0;
  52. background: ${color};
  53. mix-blend-mode: multiply;
  54. pointer-events: none;
  55. z-index: 2147483647;
  56. }
  57. `
  58. } else {
  59. styleElement.textContent = ''
  60. }
  61.  
  62. return () => {
  63. if (styleElement) {
  64. styleElement.textContent = ''
  65. }
  66. }
  67. }, [enabled, strength])
  68.  
  69. return (
  70. <NightLightContext.Provider
  71. value={{ enabled, strength, toggle, setStrength }}
  72. >
  73. {children}
  74. </NightLightContext.Provider>
  75. )
  76. }
  77.  
  78. export function useNightLight() {
  79. const context = useContext(NightLightContext)
  80. if (context === undefined) {
  81. throw new Error(
  82. 'useNightLight must be used within a NightLightProvider'
  83. )
  84. }
  85. return context
  86. }
  87. night-light-toggle.tsx
  88. ////////////////////////////////////////////////////
  89. ////////////////////////////////////////////////////
  90. 'use client'
  91.  
  92. import { Moon, Sun } from 'lucide-react'
  93.  
  94. import { Button } from '@/components/ui/common/Button'
  95. import {
  96. DropdownMenu,
  97. DropdownMenuContent,
  98. DropdownMenuItem,
  99. DropdownMenuTrigger
  100. } from '@/components/ui/common/DropdownMenu'
  101. import { Slider } from '@/components/ui/common/Slider'
  102.  
  103. import { useNightLight } from './night-light-provider'
  104.  
  105. export function NightLightToggle() {
  106. const { enabled, strength, toggle, setStrength } = useNightLight()
  107.  
  108. return (
  109. <div className='relative'>
  110. <DropdownMenu>
  111. <DropdownMenuTrigger asChild>
  112. <Button
  113. variant='outline'
  114. size='icon'
  115. className={`relative ${enabled ? 'bg-amber-100/50 hover:bg-amber-100/70' : ''}`}
  116. >
  117. <Sun
  118. className={`h-[1.2rem] w-[1.2rem] transition-all ${enabled ? 'scale-0 opacity-0' : 'scale-100 opacity-100'}`}
  119. />
  120. <Moon
  121. className={`absolute h-[1.2rem] w-[1.2rem] transition-all ${enabled ? 'scale-100 text-amber-600 opacity-100' : 'scale-0 opacity-0'}`}
  122. />
  123. <span className='sr-only'>Toggle night light</span>
  124. </Button>
  125. </DropdownMenuTrigger>
  126. <DropdownMenuContent align='end' className='w-56'>
  127. <div className='p-2'>
  128. <h4 className='mb-1 flex justify-between text-sm font-medium'>
  129. <span>Night light</span>
  130. <span className='text-amber-600'>
  131. {enabled ? `${strength}%` : 'Off'}
  132. </span>
  133. </h4>
  134. <Slider
  135. value={[strength]}
  136. min={0}
  137. max={100}
  138. step={1}
  139. onValueChange={values => setStrength(values[0])}
  140. className='my-2 w-full'
  141. disabled={!enabled}
  142. />
  143. <div className='flex justify-between text-xs text-muted-foreground'>
  144. <span>Less warm</span>
  145. <span>More warm</span>
  146. </div>
  147. </div>
  148. <DropdownMenuItem
  149. onClick={toggle}
  150. className='cursor-pointer focus:bg-amber-50'
  151. >
  152. {enabled ? 'Turn off' : 'Turn on'}
  153. </DropdownMenuItem>
  154. </DropdownMenuContent>
  155. </DropdownMenu>
  156.  
  157. {enabled && (
  158. <div className='absolute -right-1 -top-1 h-2.5 w-2.5 rounded-full border border-white bg-amber-500' />
  159. )}
  160. </div>
  161. )
  162. }
  163.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement