a tool for shared writing and social publishing
at feature/recommend 201 lines 7.4 kB view raw
1import * as Slider from "@radix-ui/react-slider"; 2import { Input } from "components/Input"; 3import { Radio } from "components/Checkbox"; 4import { useState, useEffect } from "react"; 5import { pickers } from "../ThemeSetter"; 6 7export const PubPageWidthSetter = (props: { 8 pageWidth: number | undefined; 9 setPageWidth: (value: number) => void; 10 thisPicker: pickers; 11 openPicker: pickers; 12 setOpenPicker: (p: pickers) => void; 13}) => { 14 let defaultPreset = 624; 15 let widePreset = 768; 16 17 let currentValue = props.pageWidth || defaultPreset; 18 let [interimValue, setInterimValue] = useState<number>(currentValue); 19 let [selectedPreset, setSelectedPreset] = useState< 20 "default" | "wide" | "custom" 21 >( 22 currentValue === defaultPreset 23 ? "default" 24 : currentValue === widePreset 25 ? "wide" 26 : "custom", 27 ); 28 let min = 320; 29 let max = 1200; 30 31 // Update interim value when current value changes 32 useEffect(() => { 33 setInterimValue(currentValue); 34 }, [currentValue]); 35 36 const setPageWidth = (value: number) => { 37 props.setPageWidth(value); 38 }; 39 40 let open = props.openPicker == props.thisPicker; 41 42 return ( 43 <div className="pageWidthSetter flex flex-col gap-2 px-2 py-[6px] border border-[#CCCCCC] rounded-md bg-white"> 44 <button 45 type="button" 46 className="font-bold text-[#000000] shrink-0 grow-0 w-full flex gap-2 text-left items-center" 47 onClick={() => { 48 if (!open) { 49 props.setOpenPicker(props.thisPicker); 50 } else { 51 props.setOpenPicker("null"); 52 } 53 }} 54 > 55 Max Page Width 56 <div className="flex font-normal text-[#969696]">{currentValue}px</div> 57 </button> 58 59 {open && ( 60 <div className="flex flex-col gap-1 px-3"> 61 <label htmlFor="pub-default" className="w-full"> 62 <Radio 63 radioCheckedClassName="text-[#595959]!" 64 radioEmptyClassName="text-[#969696]!" 65 type="radio" 66 id="pub-default" 67 name="pub-page-width-options" 68 value="default" 69 checked={selectedPreset === "default"} 70 onChange={(e) => { 71 if (!e.currentTarget.checked) return; 72 setSelectedPreset("default"); 73 setPageWidth(defaultPreset); 74 }} 75 > 76 <div 77 className={`w-full cursor-pointer ${selectedPreset === "default" ? "text-[#595959]" : "text-[#969696]"}`} 78 > 79 default ({defaultPreset}px) 80 </div> 81 </Radio> 82 </label> 83 <label htmlFor="pub-wide" className="w-full"> 84 <Radio 85 radioCheckedClassName="text-[#595959]!" 86 radioEmptyClassName="text-[#969696]!" 87 type="radio" 88 id="pub-wide" 89 name="pub-page-width-options" 90 value="wide" 91 checked={selectedPreset === "wide"} 92 onChange={(e) => { 93 if (!e.currentTarget.checked) return; 94 setSelectedPreset("wide"); 95 setPageWidth(widePreset); 96 }} 97 > 98 <div 99 className={`w-full cursor-pointer ${selectedPreset === "wide" ? "text-[#595959]" : "text-[#969696]"}`} 100 > 101 wide ({widePreset}px) 102 </div> 103 </Radio> 104 </label> 105 <label htmlFor="pub-custom" className="pb-3 w-full"> 106 <Radio 107 type="radio" 108 id="pub-custom" 109 name="pub-page-width-options" 110 value="custom" 111 radioCheckedClassName="text-[#595959]!" 112 radioEmptyClassName="text-[#969696]!" 113 checked={selectedPreset === "custom"} 114 onChange={(e) => { 115 if (!e.currentTarget.checked) return; 116 setSelectedPreset("custom"); 117 if (selectedPreset !== "custom") { 118 setPageWidth(currentValue); 119 setInterimValue(currentValue); 120 } 121 }} 122 > 123 <div className="flex flex-col w-full"> 124 <div className="flex gap-2"> 125 <div 126 className={`shrink-0 grow-0 w-fit z-10 cursor-pointer ${selectedPreset === "custom" ? "text-[#595959]" : "text-[#969696]"}`} 127 > 128 custom 129 </div> 130 <div 131 className={`flex font-normal ${selectedPreset === "custom" ? "text-[#969696]" : "text-[#C3C3C3]"}`} 132 > 133 <Input 134 type="number" 135 className="w-10 text-right appearance-none bg-transparent" 136 max={max} 137 min={min} 138 value={interimValue} 139 onChange={(e) => { 140 setInterimValue(parseInt(e.currentTarget.value)); 141 }} 142 onKeyDown={(e) => { 143 if (e.key === "Enter" || e.key === "Escape") { 144 e.preventDefault(); 145 let clampedValue = interimValue; 146 if (!isNaN(interimValue)) { 147 clampedValue = Math.max( 148 min, 149 Math.min(max, interimValue), 150 ); 151 setInterimValue(clampedValue); 152 } 153 setPageWidth(clampedValue); 154 } 155 }} 156 onBlur={() => { 157 let clampedValue = interimValue; 158 if (!isNaN(interimValue)) { 159 clampedValue = Math.max( 160 min, 161 Math.min(max, interimValue), 162 ); 163 setInterimValue(clampedValue); 164 } 165 setPageWidth(clampedValue); 166 }} 167 /> 168 px 169 </div> 170 </div> 171 <Slider.Root 172 className={`relative grow flex items-center select-none touch-none w-full h-fit px-1`} 173 value={[interimValue]} 174 max={max} 175 min={min} 176 step={16} 177 onValueChange={(value) => { 178 setInterimValue(value[0]); 179 }} 180 onValueCommit={(value) => { 181 setPageWidth(value[0]); 182 }} 183 > 184 <Slider.Track 185 className={`${selectedPreset === "custom" ? "bg-[#595959]" : "bg-[#C3C3C3]"} relative grow rounded-full h-[3px] my-2`} 186 /> 187 <Slider.Thumb 188 className={`flex w-4 h-4 rounded-full border-2 border-white cursor-pointer 189 ${selectedPreset === "custom" ? "bg-[#595959] shadow-[0_0_0_1px_#8C8C8C,inset_0_0_0_1px_#8C8C8C]" : "bg-[#C3C3C3]"} 190 `} 191 aria-label="Max Page Width" 192 /> 193 </Slider.Root> 194 </div> 195 </Radio> 196 </label> 197 </div> 198 )} 199 </div> 200 ); 201};