pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix TIDBSubmissionForm.tsx

Pas 59dd96e8 32b05885

+235 -180
+235 -180
src/components/player/TIDBSubmissionForm.tsx
··· 1 + import classNames from "classnames"; 1 2 import { useEffect, useRef, useState } from "react"; 3 + import { Helmet } from "react-helmet-async"; 2 4 import { useTranslation } from "react-i18next"; 3 5 4 6 import { Button } from "@/components/buttons/Button"; ··· 10 12 import { usePlayerStore } from "@/stores/player/store"; 11 13 import { usePreferencesStore } from "@/stores/preferences"; 12 14 import { submitIntro } from "@/utils/tidb"; 15 + 16 + import { IconPatch } from "../buttons/IconPatch"; 17 + import { Flare } from "../utils/Flare"; 13 18 14 19 type SegmentType = "intro" | "recap" | "credits" | "preview"; 15 20 ··· 200 205 201 206 return ( 202 207 <Modal id={submissionModal.id}> 203 - <div className="w-full max-w-[32rem] md:max-w-[50rem] lg:max-w-[60rem] m-4 px-4 max-h-[90vh] overflow-y-auto pointer-events-none"> 204 - <div className="w-full bg-modal-background rounded-xl p-6 md:p-8 pointer-events-auto"> 205 - <div className="flex items-center gap-2 mb-1"> 206 - <Icon icon={Icons.CLOCK} className="h-5 w-5 text-white" /> 207 - <Heading3 className="!mt-0 !mb-0"> 208 - {t("player.skipTime.feedback.modal.title")} 209 - </Heading3> 210 - </div> 211 - <Paragraph className="!mt-2 !mb-6 text-gray-300"> 212 - {t("player.skipTime.feedback.modal.description")} 213 - </Paragraph> 208 + <Helmet> 209 + <html data-no-scroll /> 210 + </Helmet> 211 + <div className="flex absolute inset-0 items-center justify-center pt-safe"> 212 + <Flare.Base 213 + className={classNames( 214 + "group -m-[0.705em] rounded-3xl bg-background-main", 215 + "max-w-[1200px] max-h-[650px]", 216 + "bg-mediaCard-hoverBackground/60 backdrop-filter backdrop-blur-lg shadow-lg overflow-hidden", 217 + "h-[97%] w-[95%]", 218 + "relative", 219 + )} 220 + > 221 + <div className="transition-transform duration-300 h-full relative"> 222 + <Flare.Light 223 + flareSize={300} 224 + cssColorVar="--colors-mediaCard-hoverAccent" 225 + backgroundClass="bg-modal-background duration-100" 226 + className="rounded-3xl bg-background-main group-hover:opacity-100 transition-opacity duration-300" 227 + /> 228 + <div className="absolute right-4 top-4 z-50 pointer-events-auto"> 229 + <button 230 + type="button" 231 + className="text-s font-semibold text-type-secondary hover:text-white transition-transform hover:scale-95 select-none" 232 + onClick={handleClose} 233 + > 234 + <IconPatch icon={Icons.X} /> 235 + </button> 236 + </div> 237 + <Flare.Child className="pointer-events-auto relative h-full overflow-y-auto scrollbar-none select-text p-6 pt-20 sm:pt-6"> 238 + <div className="select-text"> 239 + <div className="flex items-center gap-2 mb-1"> 240 + <Icon icon={Icons.CLOCK} className="h-5 w-5 text-white" /> 241 + <Heading3 className="!mt-0 !mb-0"> 242 + {t("player.skipTime.feedback.modal.title")} 243 + </Heading3> 244 + </div> 245 + <Paragraph className="!mt-2 !mb-6 text-gray-300"> 246 + {t("player.skipTime.feedback.modal.description")} 247 + </Paragraph> 214 248 215 - <div className="space-y-6"> 216 - {/* Section: Segment type and timestamps (example-style card) */} 217 - <div className="space-y-4 rounded-xl border border-background-secondary bg-authentication-inputBg/50 p-6"> 218 - <h2 className="text-lg font-semibold text-white"> 219 - {t("player.skipTime.feedback.modal.segmentType")} 220 - <span className="text-red-500 ml-1">*</span> 221 - </h2> 249 + <div className="space-y-6"> 250 + {/* Section: Segment type and timestamps (example-style card) */} 251 + <div className="space-y-4 rounded-xl border border-background-secondary bg-authentication-inputBg/50 p-6"> 252 + <h2 className="text-lg font-semibold text-white"> 253 + {t("player.skipTime.feedback.modal.segmentType")} 254 + <span className="text-red-500 ml-1">*</span> 255 + </h2> 222 256 223 - <div className="flex flex-wrap gap-2"> 224 - {(["intro", "recap", "credits", "preview"] as const).map( 225 - (seg) => ( 226 - <Button 227 - key={seg} 228 - theme="secondary" 229 - className={ 230 - formData.segment === seg 231 - ? "!border-2 !border-buttons-purple !bg-buttons-purple/20 focus:outline-none focus-visible:outline-none" 232 - : "!border-2 !border-background-secondary hover:!bg-authentication-inputBg focus:outline-none focus-visible:outline-none" 233 - } 234 - onClick={() => setFormData({ ...formData, segment: seg })} 235 - > 236 - {seg === "intro" 237 - ? t("player.skipTime.feedback.modal.types.intro") 238 - : seg === "recap" 239 - ? t("player.skipTime.feedback.modal.types.recap") 240 - : seg === "credits" 241 - ? t("player.skipTime.feedback.modal.types.credits") 242 - : t("player.skipTime.feedback.modal.types.preview")} 243 - </Button> 244 - ), 245 - )} 246 - </div> 257 + <div className="flex flex-wrap gap-2"> 258 + {(["intro", "recap", "credits", "preview"] as const).map( 259 + (seg) => ( 260 + <Button 261 + key={seg} 262 + theme="secondary" 263 + className={ 264 + formData.segment === seg 265 + ? "!border-2 !border-buttons-purple !bg-buttons-purple/20 focus:outline-none focus-visible:outline-none" 266 + : "!border-2 !border-background-secondary hover:!bg-authentication-inputBg focus:outline-none focus-visible:outline-none" 267 + } 268 + onClick={() => 269 + setFormData({ ...formData, segment: seg }) 270 + } 271 + > 272 + {seg === "intro" 273 + ? t("player.skipTime.feedback.modal.types.intro") 274 + : seg === "recap" 275 + ? t( 276 + "player.skipTime.feedback.modal.types.recap", 277 + ) 278 + : seg === "credits" 279 + ? t( 280 + "player.skipTime.feedback.modal.types.credits", 281 + ) 282 + : t( 283 + "player.skipTime.feedback.modal.types.preview", 284 + )} 285 + </Button> 286 + ), 287 + )} 288 + </div> 247 289 248 - <p className="text-sm text-gray-400"> 249 - {t("player.skipTime.feedback.modal.whenToDesc")} 250 - </p> 290 + <p className="text-sm text-gray-400"> 291 + {t("player.skipTime.feedback.modal.whenToDesc")} 292 + </p> 251 293 252 - <form ref={formRef} onSubmit={handleSubmit} className="space-y-4"> 253 - <div className="grid grid-cols-1 md:grid-cols-2 gap-4"> 254 - <div> 255 - <label 256 - htmlFor="tidb-start" 257 - className="block text-sm font-medium text-white mb-1" 294 + <form 295 + ref={formRef} 296 + onSubmit={handleSubmit} 297 + className="space-y-4" 258 298 > 259 - {t("player.skipTime.feedback.modal.startTimeLabel")} 260 - {formData.segment === "credits" || 261 - formData.segment === "preview" ? ( 262 - <span className="text-red-500 ml-1">*</span> 263 - ) : null} 264 - </label> 265 - <AuthInputBox 266 - value={formData.start} 267 - onChange={(value) => 268 - setFormData({ ...formData, start: value }) 269 - } 270 - placeholder={t( 271 - `player.skipTime.feedback.modal.placeholders.start.${formData.segment}`, 272 - )} 273 - /> 274 - </div> 275 - <div> 276 - <label 277 - htmlFor="tidb-end" 278 - className="block text-sm font-medium text-white mb-1" 279 - > 280 - {t("player.skipTime.feedback.modal.endTimeLabel")} 281 - {formData.segment === "intro" || 282 - formData.segment === "recap" ? ( 283 - <span className="text-red-500 ml-1">*</span> 284 - ) : null} 285 - </label> 286 - <AuthInputBox 287 - value={formData.end} 288 - onChange={(value) => 289 - setFormData({ ...formData, end: value }) 290 - } 291 - placeholder={t( 292 - `player.skipTime.feedback.modal.placeholders.end.${formData.segment}`, 293 - )} 294 - /> 295 - </div> 296 - </div> 299 + <div className="grid grid-cols-1 md:grid-cols-2 gap-4"> 300 + <div> 301 + <label 302 + htmlFor="tidb-start" 303 + className="block text-sm font-medium text-white mb-1" 304 + > 305 + {t("player.skipTime.feedback.modal.startTimeLabel")} 306 + {formData.segment === "credits" || 307 + formData.segment === "preview" ? ( 308 + <span className="text-red-500 ml-1">*</span> 309 + ) : null} 310 + </label> 311 + <AuthInputBox 312 + value={formData.start} 313 + onChange={(value) => 314 + setFormData({ ...formData, start: value }) 315 + } 316 + placeholder={t( 317 + `player.skipTime.feedback.modal.placeholders.start.${formData.segment}`, 318 + )} 319 + /> 320 + </div> 321 + <div> 322 + <label 323 + htmlFor="tidb-end" 324 + className="block text-sm font-medium text-white mb-1" 325 + > 326 + {t("player.skipTime.feedback.modal.endTimeLabel")} 327 + {formData.segment === "intro" || 328 + formData.segment === "recap" ? ( 329 + <span className="text-red-500 ml-1">*</span> 330 + ) : null} 331 + </label> 332 + <AuthInputBox 333 + value={formData.end} 334 + onChange={(value) => 335 + setFormData({ ...formData, end: value }) 336 + } 337 + placeholder={t( 338 + `player.skipTime.feedback.modal.placeholders.end.${formData.segment}`, 339 + )} 340 + /> 341 + </div> 342 + </div> 343 + 344 + {/* Timing guidance (segment-specific) */} 345 + <div className="rounded-lg border border-background-secondary bg-modal-background p-4"> 346 + <h3 className="font-semibold text-white mb-2 text-sm"> 347 + {t( 348 + `player.skipTime.feedback.modal.guide.${formData.segment}.whenToTitle`, 349 + { 350 + defaultValue: t( 351 + "player.skipTime.feedback.modal.whenToTitle", 352 + ), 353 + }, 354 + )} 355 + </h3> 356 + <div className="grid grid-cols-2 gap-3 text-xs text-gray-400"> 357 + <div> 358 + <span className="font-medium text-gray-300 block mb-0.5"> 359 + {t( 360 + "player.skipTime.feedback.modal.guide.startLabel", 361 + )} 362 + </span> 363 + {t( 364 + `player.skipTime.feedback.modal.guide.${formData.segment}.startDesc`, 365 + { 366 + defaultValue: t( 367 + "player.skipTime.feedback.modal.guide.startDesc", 368 + ), 369 + }, 370 + )} 371 + </div> 372 + <div> 373 + <span className="font-medium text-gray-300 block mb-0.5"> 374 + {t( 375 + "player.skipTime.feedback.modal.guide.endLabel", 376 + )} 377 + </span> 378 + {t( 379 + `player.skipTime.feedback.modal.guide.${formData.segment}.endDesc`, 380 + { 381 + defaultValue: t( 382 + "player.skipTime.feedback.modal.guide.endDesc", 383 + ), 384 + }, 385 + )} 386 + </div> 387 + <div> 388 + <span className="font-medium text-gray-300 block mb-0.5"> 389 + {t( 390 + "player.skipTime.feedback.modal.guide.durationLabel", 391 + )} 392 + </span> 393 + {t( 394 + `player.skipTime.feedback.modal.guide.${formData.segment}.durationDesc`, 395 + { 396 + defaultValue: t( 397 + "player.skipTime.feedback.modal.guide.durationDesc", 398 + ), 399 + }, 400 + )} 401 + </div> 402 + <div> 403 + <span className="font-medium text-gray-300 block mb-0.5"> 404 + {t( 405 + "player.skipTime.feedback.modal.guide.excludeLabel", 406 + )} 407 + </span> 408 + {t( 409 + `player.skipTime.feedback.modal.guide.${formData.segment}.excludeDesc`, 410 + { 411 + defaultValue: t( 412 + "player.skipTime.feedback.modal.guide.excludeDesc", 413 + ), 414 + }, 415 + )} 416 + </div> 417 + </div> 418 + </div> 297 419 298 - {/* Timing guidance (segment-specific) */} 299 - <div className="rounded-lg border border-background-secondary bg-modal-background p-4"> 300 - <h3 className="font-semibold text-white mb-2 text-sm"> 301 - {t( 302 - `player.skipTime.feedback.modal.guide.${formData.segment}.whenToTitle`, 303 - { 304 - defaultValue: t( 305 - "player.skipTime.feedback.modal.whenToTitle", 306 - ), 307 - }, 308 - )} 309 - </h3> 310 - <div className="grid grid-cols-2 gap-3 text-xs text-gray-400"> 311 - <div> 312 - <span className="font-medium text-gray-300 block mb-0.5"> 313 - {t("player.skipTime.feedback.modal.guide.startLabel")} 314 - </span> 315 - {t( 316 - `player.skipTime.feedback.modal.guide.${formData.segment}.startDesc`, 317 - { 318 - defaultValue: t( 319 - "player.skipTime.feedback.modal.guide.startDesc", 320 - ), 321 - }, 322 - )} 323 - </div> 324 - <div> 325 - <span className="font-medium text-gray-300 block mb-0.5"> 326 - {t("player.skipTime.feedback.modal.guide.endLabel")} 327 - </span> 328 - {t( 329 - `player.skipTime.feedback.modal.guide.${formData.segment}.endDesc`, 330 - { 331 - defaultValue: t( 332 - "player.skipTime.feedback.modal.guide.endDesc", 333 - ), 334 - }, 335 - )} 336 - </div> 337 - <div> 338 - <span className="font-medium text-gray-300 block mb-0.5"> 339 - {t( 340 - "player.skipTime.feedback.modal.guide.durationLabel", 341 - )} 342 - </span> 343 - {t( 344 - `player.skipTime.feedback.modal.guide.${formData.segment}.durationDesc`, 345 - { 346 - defaultValue: t( 347 - "player.skipTime.feedback.modal.guide.durationDesc", 348 - ), 349 - }, 350 - )} 351 - </div> 352 - <div> 353 - <span className="font-medium text-gray-300 block mb-0.5"> 354 - {t("player.skipTime.feedback.modal.guide.excludeLabel")} 355 - </span> 356 - {t( 357 - `player.skipTime.feedback.modal.guide.${formData.segment}.excludeDesc`, 358 - { 359 - defaultValue: t( 360 - "player.skipTime.feedback.modal.guide.excludeDesc", 361 - ), 362 - }, 363 - )} 364 - </div> 420 + <div className="flex gap-2 pt-2 justify-between"> 421 + <Button 422 + theme="secondary" 423 + onClick={handleClose} 424 + disabled={isSubmitting} 425 + > 426 + {t("player.skipTime.feedback.modal.cancel")} 427 + </Button> 428 + <Button 429 + theme="purple" 430 + disabled={isSubmitting} 431 + loading={isSubmitting} 432 + icon={Icons.ARROW_RIGHT} 433 + onClick={() => formRef.current?.requestSubmit()} 434 + > 435 + {isSubmitting 436 + ? t("player.skipTime.feedback.modal.submitting") 437 + : t("player.skipTime.feedback.modal.submit")} 438 + </Button> 439 + </div> 440 + </form> 365 441 </div> 366 442 </div> 367 - 368 - <div className="flex gap-2 pt-2 justify-between"> 369 - <Button 370 - theme="secondary" 371 - onClick={handleClose} 372 - disabled={isSubmitting} 373 - > 374 - {t("player.skipTime.feedback.modal.cancel")} 375 - </Button> 376 - <Button 377 - theme="purple" 378 - disabled={isSubmitting} 379 - loading={isSubmitting} 380 - icon={Icons.ARROW_RIGHT} 381 - onClick={() => formRef.current?.requestSubmit()} 382 - > 383 - {isSubmitting 384 - ? t("player.skipTime.feedback.modal.submitting") 385 - : t("player.skipTime.feedback.modal.submit")} 386 - </Button> 387 - </div> 388 - </form> 389 - </div> 443 + </div> 444 + </Flare.Child> 390 445 </div> 391 - </div> 446 + </Flare.Base> 392 447 </div> 393 448 </Modal> 394 449 );