jbilcke-hf HF staff commited on
Commit
2e9848b
1 Parent(s): 7d9ad19

update tooltip

Browse files
Files changed (2) hide show
  1. src/app/layout.tsx +1 -1
  2. src/app/main.tsx +501 -474
src/app/layout.tsx CHANGED
@@ -16,7 +16,7 @@ export default function RootLayout({
16
  return (
17
  <html lang="en">
18
  <body className={cn(
19
- `h-full w-full overflow-none light`,
20
  salsa.className
21
  )}>
22
  {children}
 
16
  return (
17
  <html lang="en">
18
  <body className={cn(
19
+ `h-full w-full overflow-none dark`,
20
  salsa.className
21
  )}>
22
  {children}
src/app/main.tsx CHANGED
@@ -39,6 +39,7 @@ import { FileContent } from "use-file-picker/dist/interfaces"
39
  import { generateRandomStory } from "@/lib/utils/generateRandomStory"
40
  import { logImage } from "@/lib/utils/logImage"
41
  import { defaultPrompt } from "./config"
 
42
 
43
  export function Main() {
44
  const [storyPromptDraft, setStoryPromptDraft] = useLocalStorage<string>(
@@ -584,532 +585,558 @@ export function Main() {
584
  }, [queryStringPrompt, queryStringAutorun, queryStringOrientation])
585
 
586
  return (
587
- <div className={cn(
588
- `fixed`,
589
- // `bg-zinc-800`,
590
- // old style, more "amber"
591
- // `bg-gradient-to-br from-amber-600 to-yellow-500`,
592
-
593
- // nice style!
594
- // `bg-gradient-to-br from-amber-700 to-yellow-300`,
595
-
596
- // warm orange, a bit flash but not bad, not bad at all
597
- // `bg-gradient-to-br from-orange-700 to-yellow-400`,
598
-
599
- // nice "AiTube" vibe
600
- // `bg-gradient-to-br from-red-700 to-yellow-400`,
601
-
602
- // pretty cool lime!
603
- `bg-gradient-to-br from-lime-700 to-yellow-400`,
604
-
605
- // new style, pretty "fresh" - maybe too bright?
606
- // use a dark logo for this one
607
- // `bg-gradient-to-br from-yellow-200 to-yellow-500`,
608
-
609
- // too pastel
610
- // `bg-gradient-to-br from-yellow-200 to-red-300`,
611
-
612
- // `bg-gradient-to-br from-sky-400 to-sky-300/30`,
613
- `w-screen h-full overflow-y-scroll md:overflow-hidden`,
614
- )}
615
- style={{ boxShadow: "inset 0 0px 250px 0 rgb(0 0 0 / 60%)" }}>
616
- <div className="flex flex-col w-screen h-screen">
617
- <div className="
618
- flex flex-col md:flex-row w-full
619
- items-center md:justify-center
620
- flex-1
621
- "
622
  >
623
- <div className={cn(
624
- `flex flex-col md:h-full md:items-center md:justify-center`,
625
- `w-full md:w-1/2`,
626
- `transition-all duration-200 ease-in-out`,
627
- `ml-0`,
628
- `pt-4 sm:pt-0`,
629
- )}>
630
- <Card className={cn(
631
- // `shadow-2xl z-30 rounded-3xl`,
632
- `shadow-none`,
633
- `w-full md:ml-[12%] md:w-[95%]`,
634
  `transition-all duration-200 ease-in-out`,
635
- `bg-transparent dark:bg-transparent`,
636
- // `backdrop-blur-2xl dark:backdrop-blur-2xl`,
637
- // `bg-amber-500 dark:bg-amber-500`,
638
-
639
- `border-transparent`,
640
- // `bg-stone-50/90 dark:bg-stone-50/90`,
641
- // `border-yellow-100 dark:border-yellow-100`,
642
- // `bg-yellow-500 dark:bg-yellow-500`,
643
- // `border-yellow-400 dark:border-yellow-400`,
644
-
645
  )}>
646
- <CardHeader>
647
- <div className="flex flex-col justify-start">
648
- <div className="
649
- flex flex-row
650
- items-center justify-center
651
- transition-all duration-200 ease-in-out
652
- px-3
653
-
654
- rounded-full">
655
- <div
656
- className="
657
- flex
 
 
 
 
 
 
 
 
 
 
658
  transition-all duration-200 ease-in-out
659
- items-center justify-center text-center
660
- w-10 h-10 md:w-12 md:h-12 lg:w-16 lg:h-16
661
- text-3xl md:text-4xl lg:text-5xl
662
- rounded-lg
663
- mr-2
664
- font-sans
665
- bg-amber-400 dark:bg-amber-400
666
-
667
- text-stone-950/80 dark:text-stone-950/80 font-bold
668
- "
669
- >AI</div>
670
  <div
671
- className="
 
672
  transition-all duration-200 ease-in-out
673
- text-amber-400 dark:text-amber-400
 
674
  text-3xl md:text-4xl lg:text-5xl
 
 
 
 
 
 
675
  "
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
676
 
677
- style={{ textShadow: "#00000035 0px 0px 2px" }}
678
-
679
- /*
680
  className="
681
- text-5xl
682
- bg-gradient-to-br from-yellow-300 to-yellow-500
683
- inline-block text-transparent bg-clip-text
684
- py-6
 
685
  "
686
- */
687
- >Stories Factory</div>
688
  </div>
689
-
690
- <p
691
- className="
692
- transition-all duration-200 ease-in-out
693
- text-stone-900/90 dark:text-stone-100/90
694
- text-lg md:text-xl lg:text-2xl
695
- text-center
696
- pt-2 md:pt-4
697
- "
698
- style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}
699
- >Make video stories using AI ✨</p>
700
- </div>
701
- </CardHeader>
702
- <CardContent
703
- className="flex flex-col space-y-3"
704
- >
705
-
706
- {/* LEFT MENU BUTTONS + MAIN PROMPT INPUT */}
707
- <div className="flex flex-row space-x-3 w-full">
708
 
709
-
710
- {/*
711
 
712
- TODO: To finish by Julian a bit later
713
 
714
- <div className="
715
- flex flex-col
716
-
717
- w-32 bg-yellow-600
718
- transition-all duration-200 ease-in-out
719
- space-y-2 md:space-y-4
720
- ">
721
- <Input
722
- type="file"
723
- className=""
724
- onChange={async (e: React.ChangeEvent<HTMLInputElement>) => {
725
- if (e.target.files && e.target.files.length > 0) {
726
- const file = e.target.files[0];
727
- const newImageBase64 = await fileToBase64(file)
728
- setMainCharacterImage(newImageBase64)
729
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
730
  }}
731
- accept="image/*"
 
 
 
 
 
 
 
732
  />
733
- </div>
734
- */}
 
 
735
 
736
- {/* MAIN PROMPT INPUT */}
737
- <div className="
738
- flex flex-col
739
- flex-1
740
- transition-all duration-200 ease-in-out
741
- space-y-2 md:space-y-4
742
- ">
743
- <TextareaField
744
- id="story-prompt-draft"
745
- // label="My story:"
746
- // disabled={modelState != 'ready'}
747
- onChange={(e) => {
748
- setStoryPromptDraft(e.target.value)
749
- promptDraftRef.current = e.target.value
750
- }}
751
- placeholder={defaultPrompt}
752
- inputClassName="
753
- transition-all duration-200 ease-in-out
754
- h-32 md:h-56 lg:h-64
755
-
756
- "
757
- disabled={isBusy}
758
- value={storyPromptDraft}
759
- />
760
-
761
-
762
- {/* END OF MAIN PROMPT INPUT */}
763
  </div>
764
 
765
- {/* END OF LEFT MENU BUTTONS + MAIN PROMPT INPUT */}
766
- </div>
767
 
768
- {/* ACTION BAR */}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
769
 
770
- <div className="
771
- w-full
772
- flex flex-row
773
- justify-between items-center
774
- space-x-3">
775
-
776
- {/*
777
- <Button
778
- onClick={() => load()}
779
- disabled={isBusy}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
780
  // variant="ghost"
781
  className={cn(
782
- `text-sm md:text-base lg:text-lg`,
783
  `bg-stone-800/90 text-amber-400/100 dark:bg-stone-800/90 dark:text-amber-400/100`,
784
  `font-bold`,
785
  `hover:bg-stone-800/100 hover:text-amber-300/100 dark:hover:bg-stone-800/100 dark:hover:text-amber-300/100`,
786
  storyPromptDraft ? "opacity-100" : "opacity-80"
787
  )}
788
  >
789
- <span className="mr-1">Load project</span>
790
- </Button>
791
- */}
792
-
793
- <div className="
794
-
795
- flex flex-row
796
- justify-between items-center
797
- space-x-3">
798
-
799
-
800
- {canSeeBetaFeatures && <Button
801
- onClick={openFilePicker}
802
- disabled={isBusy}
803
- // variant="ghost"
804
- className={cn(
805
- `text-sm md:text-base lg:text-lg`,
806
- `bg-stone-800/90 text-amber-400/100 dark:bg-stone-800/90 dark:text-amber-400/100`,
807
- `font-bold`,
808
- `hover:bg-stone-800/100 hover:text-amber-300/100 dark:hover:bg-stone-800/100 dark:hover:text-amber-300/100`,
809
- storyPromptDraft ? "opacity-100" : "opacity-80"
810
- )}
811
- >
812
- <span className="hidden xl:inline mr-1">Load</span>
813
- <span className="inline xl:hidden mr-1">Load</span>
814
- </Button>}
815
-
816
-
817
-
818
- {canSeeBetaFeatures ?
819
- <Button
820
- onClick={() => saveClap()}
821
- disabled={!currentClap || isBusy}
822
- // variant="ghost"
823
- className={cn(
824
- `text-sm md:text-base lg:text-lg`,
825
- `bg-stone-800/90 text-amber-400/100 dark:bg-stone-800/90 dark:text-amber-400/100`,
826
- `font-bold`,
827
- `hover:bg-stone-800/100 hover:text-amber-300/100 dark:hover:bg-stone-800/100 dark:hover:text-amber-300/100`,
828
- storyPromptDraft ? "opacity-100" : "opacity-80"
829
- )}
830
- >
831
- <span className="hidden xl:inline mr-1">Save</span>
832
- <span className="inline xl:hidden mr-1">Save</span>
833
- </Button> : <div></div>
834
- }
835
- </div>
836
-
837
- <div className="
838
- flex flex-row
839
- justify-between items-center
840
- space-x-3
841
- select-none
842
- ">
843
-
844
-
845
- {/* RANDOMNESS SWITCH */}
846
  <div className="
847
  flex flex-row
848
  justify-between items-center
849
- cursor-pointer
850
- transition-all duration-150 ease-in-out
851
- hover:scale-110 active:scale-150
852
- text-stone-800
853
- hover:text-stone-950
854
- active:text-black
855
- group
856
- "
857
- onClick={() => {
858
- const randomStory = generateRandomStory()
859
- setStoryPromptDraft(randomStory)
860
- promptDraftRef.current = randomStory
861
- }}>
862
- <div>
863
- </div>
864
- <div className="
865
- w-6 h-8
866
- flex flex-row items-center justify-center
867
- transition-all duration-150 ease-out
868
- group-hover:animate-swing
869
  "
870
- >
871
- <GiRollingDices size={24} />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
872
  </div>
873
- </div>
874
- {/* END OF RANDOMNESS SWITCH */}
875
 
876
 
877
- {/* ORIENTATION SWITCH */}
878
- <div className="
879
- flex flex-row
880
- justify-between items-center
881
- cursor-pointer
882
- transition-all duration-150 ease-out
883
- hover:scale-110 active:scale-150
884
- text-stone-800
885
- hover:text-stone-950
886
- active:text-black
887
- group
888
- "
889
- onClick={() => toggleOrientation()}>
890
- <div>
891
- </div>
892
- <div className="
893
- w-8 h-8
894
- flex flex-row items-center justify-center
895
- transition-all duration-150 ease-in-out
896
- group-hover:animate-swing
897
  "
898
- >
899
- <div className={cn(
900
- `transition-all duration-200 ease-in-out`,
901
- orientation === ClapMediaOrientation.LANDSCAPE ? `rotate-90` : `rotate-0`
902
- )}>
903
- <IoMdPhonePortrait size={24} />
 
 
 
 
 
 
 
 
 
 
904
  </div>
905
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
906
  </div>
907
- {/* END OF ORIENTATION SWITCH */}
908
- <Button
909
- onClick={handleSubmit}
910
- disabled={!storyPromptDraft || isBusy}
911
- // variant="ghost"
912
- className={cn(
913
- `text-base md:text-lg lg:text-xl xl:text-2xl`,
914
- `bg-stone-800/90 text-amber-400/100 dark:bg-stone-800/90 dark:text-amber-400/100`,
915
- `font-bold`,
916
- `hover:bg-stone-800/100 hover:text-amber-300/100 dark:hover:bg-stone-800/100 dark:hover:text-amber-300/100`,
917
- storyPromptDraft ? "opacity-100" : "opacity-80"
918
- )}
919
- >
920
- <span className="mr-1.5">Create</span><span className="hidden md:inline">👉</span><span className="inline md:hidden">👇</span>
921
- </Button>
922
  </div>
923
 
924
- {/* END OF ACTION BAR */}
925
- </div>
 
 
 
 
 
926
 
927
- </CardContent>
928
- </Card>
929
- </div>
930
- <div className={cn(
931
- `flex flex-col items-center justify-center`,
932
- `flex-1 h-full`,
933
- // `transition-all duration-200 ease-in-out`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
934
 
935
- `-mt-[20px] -mb-[90px] md:-mt-0 md:-mb-0`,
936
- )}>
937
-
938
- <div className={cn(`
939
- -mt-8 md:mt-0
940
- transition-all duration-200 ease-in-out
941
- `,
942
- isLandscape
943
- ? `scale-[0.9] md:scale-[0.75] lg:scale-[0.9] xl:scale-[1.0] 2xl:scale-[1.1]`
944
- : `scale-[0.8] md:scale-[0.9] lg:scale-[1.1]`
945
- )}>
946
- <DeviceFrameset
947
- device="Nexus 5"
948
- // color="black"
949
-
950
- landscape={isLandscape}
951
-
952
- // note 1: videos are generated in 1024x576 or 576x1024
953
- // so we need to keep the same ratio here
954
-
955
- // note 2: width and height are fixed, if width always stays 512
956
- // that's because the landscape={} parameter will do the switch for us
957
-
958
- width={288}
959
- height={512}
960
- >
961
- <div className="
962
- flex flex-col items-center justify-center
963
- w-full h-full
964
- bg-black text-white
965
- ">
966
- {isBusy ? <div className="
967
- flex flex-col
968
- items-center justify-center
969
- text-center space-y-1.5">
970
- <p className="text-2xl font-bold">{progress}%</p>
971
- <p className="text-base text-white/70">{isBusy
972
- ? (
973
- // note: some of those tasks are running in parallel,
974
- // and some are super-slow (like music or video)
975
- // by carefully selecting in which order we set the ternaries,
976
- // we can create the illusion that we just have a succession of reasonably-sized tasks
977
- storyGenerationStatus === "generating" ? "Writing story.."
978
- : parseGenerationStatus === "generating" ? "Loading the project.."
979
- : assetGenerationStatus === "generating" ? "Casting characters.."
980
- : imageGenerationStatus === "generating" ? "Creating storyboards.."
981
- : soundGenerationStatus === "generating" ? "Recording sounds.."
982
- : videoGenerationStatus === "generating" ? "Filming shots.."
983
- : musicGenerationStatus === "generating" ? "Producing music.."
984
- : voiceGenerationStatus === "generating" ? "Recording dialogues.."
985
- : finalGenerationStatus === "generating" ? "Editing final cut.."
986
- : "Please wait.."
987
- )
988
- : status === "error"
989
- ? <span>{error || ""}</span>
990
- : <span>{error ? error : <span>&nbsp;</span>}</span> // to prevent layout changes
991
- }</p>
992
- </div>
993
- : (currentVideo && currentVideo?.length > 128) ? <video
994
- src={currentVideo}
995
- controls
996
- playsInline
997
- // I think we can't autoplay with sound,
998
- // so let's disable auto-play
999
- // autoPlay
1000
- // muted
1001
- loop
1002
- className="object-cover"
1003
- style={{
1004
- }}
1005
- /> : <div className="
1006
- flex flex-col
1007
  items-center justify-center
1008
- text-lg text-center"></div>}
1009
- </div>
1010
-
1011
- <div className={cn(`
1012
- fixed
1013
- flex flex-row items-center justify-center
1014
- bg-transparent
1015
- font-sans
1016
- -mb-0
1017
- `,
1018
- isLandscape ? 'h-4' : 'h-14'
1019
- )}
1020
- style={{ width: isPortrait ? 288 : 512 }}>
1021
- <span className="text-stone-100/50 text-4xs"
1022
- style={{ textShadow: "rgb(0 0 0 / 80%) 0px 0px 2px" }}>
1023
- Powered by
1024
- </span>
1025
- <span className="ml-1 mr-0.5">
1026
- <Image src={HFLogo} alt="Hugging Face" width={14} height={13} />
1027
- </span>
1028
- <span className="text-stone-100/80 text-3xs font-semibold"
1029
- style={{ textShadow: "rgb(0 0 0 / 80%) 0px 0px 2px" }}>Hugging Face</span>
1030
 
1031
- </div>
1032
- </DeviceFrameset>
1033
-
1034
- {(currentVideo && currentVideo.length > 128) ? <div
1035
- className={cn(`
1036
- w-full
1037
- flex flex-row
1038
- items-center justify-center
1039
- transition-all duration-150 ease-in-out
1040
-
1041
- text-stone-800
1042
-
1043
- group
1044
- pt-2 md:pt-4
1045
- `,
1046
- isBusy ? 'opacity-50' : 'cursor-pointer opacity-100 hover:scale-110 active:scale-150 hover:text-stone-950 active:text-black'
1047
- )}
1048
- style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}
1049
- onClick={isBusy ? undefined : saveVideo}
1050
- >
1051
- <div className="
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1052
  text-base md:text-lg lg:text-xl
1053
  transition-all duration-150 ease-out
1054
  group-hover:animate-swing
1055
- "><FaCloudDownloadAlt /></div>
1056
- <div className="text-xs md:text-sm lg:text-base">&nbsp;Download</div>
1057
- </div> : null}
1058
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1059
  </div>
1060
  </div>
1061
- <div
1062
- className="
1063
- fixed
1064
-
1065
- left-8
1066
- bottom-4
1067
- flex flex-col md:flex-row
1068
- items-center justify-center
1069
- space-y-4 md:space-x-4 md:space-y-0
1070
-
1071
- ">
1072
- <a
1073
- className="
1074
- flex
1075
- no-underline
1076
- animation-all duration-150 ease-in-out
1077
- group
1078
- text-stone-950/60 hover:text-stone-950/80 scale-95 hover:scale-100"
1079
- href="https://discord.gg/AEruz9B92B"
1080
- target="_blank">
1081
- <div className="
1082
- text-base md:text-lg lg:text-xl
1083
- transition-all duration-150 ease-out
1084
- group-hover:animate-swing
1085
- "><FaDiscord /></div>
1086
- <div className="text-xs md:text-sm lg:text-base ml-1.5">
1087
- <span className="hidden md:block">Chat on Discord</span>
1088
- <span className="block md:hidden">Discord</span>
1089
- </div>
1090
- </a>
1091
- <a
1092
- className="
1093
- flex
1094
- no-underline
1095
- animation-all duration-150 ease-in-out
1096
- group
1097
- text-stone-950/60 hover:text-stone-950/80 scale-95 hover:scale-100"
1098
- href="https://latent-store.notion.site/AI-Stories-Academy-8e3ce6ff2d5946ffadc94193619dd5cd"
1099
- target="_blank">
1100
- <div className="
1101
- text-base md:text-lg lg:text-xl
1102
- transition-all duration-150 ease-out
1103
- group-hover:animate-swing
1104
- "><GiSpellBook /></div>
1105
- <div className="text-xs md:text-sm lg:text-base ml-1.5">
1106
- <span className="hidden md:block">Prompt spells</span>
1107
- <span className="block md:hidden">Prompt spells</span>
1108
- </div>
1109
- </a>
1110
- </div>
1111
  </div>
1112
- <Toaster />
1113
- </div>
1114
  );
1115
  }
 
39
  import { generateRandomStory } from "@/lib/utils/generateRandomStory"
40
  import { logImage } from "@/lib/utils/logImage"
41
  import { defaultPrompt } from "./config"
42
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
43
 
44
  export function Main() {
45
  const [storyPromptDraft, setStoryPromptDraft] = useLocalStorage<string>(
 
585
  }, [queryStringPrompt, queryStringAutorun, queryStringOrientation])
586
 
587
  return (
588
+ <TooltipProvider>
589
+ <div className={cn(
590
+ `fixed`,
591
+ // `bg-zinc-800`,
592
+ // old style, more "amber"
593
+ // `bg-gradient-to-br from-amber-600 to-yellow-500`,
594
+
595
+ // nice style!
596
+ // `bg-gradient-to-br from-amber-700 to-yellow-300`,
597
+
598
+ // warm orange, a bit flash but not bad, not bad at all
599
+ // `bg-gradient-to-br from-orange-700 to-yellow-400`,
600
+
601
+ // nice "AiTube" vibe
602
+ // `bg-gradient-to-br from-red-700 to-yellow-400`,
603
+
604
+ // pretty cool lime!
605
+ `bg-gradient-to-br from-lime-700 to-yellow-400`,
606
+
607
+ // new style, pretty "fresh" - maybe too bright?
608
+ // use a dark logo for this one
609
+ // `bg-gradient-to-br from-yellow-200 to-yellow-500`,
610
+
611
+ // too pastel
612
+ // `bg-gradient-to-br from-yellow-200 to-red-300`,
613
+
614
+ // `bg-gradient-to-br from-sky-400 to-sky-300/30`,
615
+ `w-screen h-full overflow-y-scroll md:overflow-hidden`,
616
+ )}
617
+
618
+ // this version is a bit too aggressive on mobile
619
+ // style={{ boxShadow: "inset 0 0px 250px 0 rgb(0 0 0 / 60%)" }}
620
+
621
+ style={{ boxShadow: "inset 0 0 10vh 0 rgb(0 0 0 / 50%)" }}
 
622
  >
623
+ <div className="flex flex-col w-screen h-screen">
624
+ <div className="
625
+ flex flex-col md:flex-row w-full
626
+ items-center md:justify-center
627
+ flex-1
628
+ "
629
+ >
630
+ <div className={cn(
631
+ `flex flex-col md:h-full md:items-center md:justify-center`,
632
+ `w-full md:w-1/2`,
 
633
  `transition-all duration-200 ease-in-out`,
634
+ `ml-0`,
635
+ `pt-4 sm:pt-0`,
 
 
 
 
 
 
 
 
636
  )}>
637
+ <Card className={cn(
638
+ // `shadow-2xl z-30 rounded-3xl`,
639
+ `shadow-none`,
640
+ `w-full md:ml-[12%] md:w-[95%]`,
641
+ `transition-all duration-200 ease-in-out`,
642
+ `bg-transparent dark:bg-transparent`,
643
+ // `backdrop-blur-2xl dark:backdrop-blur-2xl`,
644
+ // `bg-amber-500 dark:bg-amber-500`,
645
+
646
+
647
+ `border-transparent dark:border-transparent`,
648
+ // `bg-stone-50/90 dark:bg-stone-50/90`,
649
+ // `border-yellow-100 dark:border-yellow-100`,
650
+ // `bg-yellow-500 dark:bg-yellow-500`,
651
+ // `border-yellow-400 dark:border-yellow-400`,
652
+
653
+ )}>
654
+ <CardHeader>
655
+ <div className="flex flex-col justify-start">
656
+ <div className="
657
+ flex flex-row
658
+ items-center justify-center
659
  transition-all duration-200 ease-in-out
660
+ px-3
661
+
662
+ rounded-full">
 
 
 
 
 
 
 
 
663
  <div
664
+ className="
665
+ flex
666
  transition-all duration-200 ease-in-out
667
+ items-center justify-center text-center
668
+ w-10 h-10 md:w-12 md:h-12 lg:w-16 lg:h-16
669
  text-3xl md:text-4xl lg:text-5xl
670
+ rounded-lg
671
+ mr-2
672
+ font-sans
673
+ bg-amber-400 dark:bg-amber-400
674
+
675
+ text-stone-950/80 dark:text-stone-950/80 font-bold
676
  "
677
+ >AI</div>
678
+ <div
679
+ className="
680
+ transition-all duration-200 ease-in-out
681
+ text-amber-400 dark:text-amber-400
682
+ text-3xl md:text-4xl lg:text-5xl
683
+ "
684
+
685
+ style={{ textShadow: "#00000035 0px 0px 2px" }}
686
+
687
+ /*
688
+ className="
689
+ text-5xl
690
+ bg-gradient-to-br from-yellow-300 to-yellow-500
691
+ inline-block text-transparent bg-clip-text
692
+ py-6
693
+ "
694
+ */
695
+ >Stories Factory</div>
696
+ </div>
697
 
698
+ <p
 
 
699
  className="
700
+ transition-all duration-200 ease-in-out
701
+ text-stone-900/90 dark:text-stone-900/90
702
+ text-lg md:text-xl lg:text-2xl
703
+ text-center
704
+ pt-2 md:pt-4
705
  "
706
+ style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}
707
+ >Make video stories using AI ✨</p>
708
  </div>
709
+ </CardHeader>
710
+ <CardContent
711
+ className="flex flex-col space-y-3"
712
+ >
713
+
714
+ {/* LEFT MENU BUTTONS + MAIN PROMPT INPUT */}
715
+ <div className="flex flex-row space-x-3 w-full">
716
+
 
 
 
 
 
 
 
 
 
 
 
717
 
718
+ {/*
 
719
 
720
+ TODO: To finish by Julian a bit later
721
 
722
+ <div className="
723
+ flex flex-col
724
+
725
+ w-32 bg-yellow-600
726
+ transition-all duration-200 ease-in-out
727
+ space-y-2 md:space-y-4
728
+ ">
729
+ <Input
730
+ type="file"
731
+ className=""
732
+ onChange={async (e: React.ChangeEvent<HTMLInputElement>) => {
733
+ if (e.target.files && e.target.files.length > 0) {
734
+ const file = e.target.files[0];
735
+ const newImageBase64 = await fileToBase64(file)
736
+ setMainCharacterImage(newImageBase64)
737
+ }
738
+ }}
739
+ accept="image/*"
740
+ />
741
+ </div>
742
+ */}
743
+
744
+ {/* MAIN PROMPT INPUT */}
745
+ <div className="
746
+ flex flex-col
747
+ flex-1
748
+ transition-all duration-200 ease-in-out
749
+ space-y-2 md:space-y-4
750
+ ">
751
+ <TextareaField
752
+ id="story-prompt-draft"
753
+ // label="My story:"
754
+ // disabled={modelState != 'ready'}
755
+ onChange={(e) => {
756
+ setStoryPromptDraft(e.target.value)
757
+ promptDraftRef.current = e.target.value
758
  }}
759
+ placeholder={defaultPrompt}
760
+ inputClassName="
761
+ transition-all duration-200 ease-in-out
762
+ h-32 md:h-56 lg:h-64
763
+
764
+ "
765
+ disabled={isBusy}
766
+ value={storyPromptDraft}
767
  />
768
+
769
+
770
+ {/* END OF MAIN PROMPT INPUT */}
771
+ </div>
772
 
773
+ {/* END OF LEFT MENU BUTTONS + MAIN PROMPT INPUT */}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
774
  </div>
775
 
776
+ {/* ACTION BAR */}
 
777
 
778
+ <div className="
779
+ w-full
780
+ flex flex-col lg:flex-row
781
+ justify-between items-center
782
+ space-y-3 lg:space-x-3 lg:space-y-0">
783
+
784
+ {/*
785
+ <Button
786
+ onClick={() => load()}
787
+ disabled={isBusy}
788
+ // variant="ghost"
789
+ className={cn(
790
+ `text-sm md:text-base lg:text-lg`,
791
+ `bg-stone-800/90 text-amber-400/100 dark:bg-stone-800/90 dark:text-amber-400/100`,
792
+ `font-bold`,
793
+ `hover:bg-stone-800/100 hover:text-amber-300/100 dark:hover:bg-stone-800/100 dark:hover:text-amber-300/100`,
794
+ storyPromptDraft ? "opacity-100" : "opacity-80"
795
+ )}
796
+ >
797
+ <span className="mr-1">Load project</span>
798
+ </Button>
799
+ */}
800
 
801
+ <div className="
802
+
803
+ flex flex-row
804
+ justify-between items-center
805
+ space-x-3">
806
+
807
+
808
+ {canSeeBetaFeatures &&
809
+ <Tooltip>
810
+ <TooltipTrigger>
811
+ <Button
812
+ onClick={openFilePicker}
813
+ disabled={isBusy}
814
+ // variant="ghost"
815
+ className={cn(
816
+ `text-xs md:text-sm lg:text-base`,
817
+ `bg-stone-800/90 text-amber-400/100 dark:bg-stone-800/90 dark:text-amber-400/100`,
818
+ `font-bold`,
819
+ `hover:bg-stone-800/100 hover:text-amber-300/100 dark:hover:bg-stone-800/100 dark:hover:text-amber-300/100`,
820
+ storyPromptDraft ? "opacity-100" : "opacity-80"
821
+ )}
822
+ >
823
+ <span className="hidden xl:inline mr-1">Load .clap</span>
824
+ <span className="inline xl:hidden mr-1">Load .clap</span>
825
+ </Button>
826
+ </TooltipTrigger>
827
+ <TooltipContent side="top">
828
+ <p className="text-xs font-normal text-stone-100/90 text-center">
829
+ Clap is a new AI format,<br/>check out the academy<br/>to learn more about it.
830
+ </p>
831
+ </TooltipContent>
832
+ </Tooltip>}
833
+
834
+
835
+
836
+ {canSeeBetaFeatures &&
837
+ <Tooltip>
838
+ <TooltipTrigger>
839
+ <Button
840
+ onClick={() => saveClap()}
841
+ disabled={!currentClap || isBusy}
842
  // variant="ghost"
843
  className={cn(
844
+ `text-xs md:text-sm lg:text-base`,
845
  `bg-stone-800/90 text-amber-400/100 dark:bg-stone-800/90 dark:text-amber-400/100`,
846
  `font-bold`,
847
  `hover:bg-stone-800/100 hover:text-amber-300/100 dark:hover:bg-stone-800/100 dark:hover:text-amber-300/100`,
848
  storyPromptDraft ? "opacity-100" : "opacity-80"
849
  )}
850
  >
851
+ <span className="hidden xl:inline mr-1">Save .clap</span>
852
+ <span className="inline xl:hidden mr-1">Save .clap</span>
853
+ </Button> </TooltipTrigger>
854
+ <TooltipContent side="top">
855
+ <p className="text-xs font-normal text-stone-100/90 text-center">
856
+ Clap is a new AI format,<br/>check out the academy<br/>to learn more about it.
857
+ </p>
858
+ </TooltipContent>
859
+ </Tooltip>
860
+ }
861
+ </div>
862
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
863
  <div className="
864
  flex flex-row
865
  justify-between items-center
866
+ space-x-3
867
+ select-none
868
+ ">
869
+
870
+
871
+ {/* RANDOMNESS SWITCH */}
872
+ <div className="
873
+ flex flex-row
874
+ justify-between items-center
875
+ cursor-pointer
876
+ transition-all duration-150 ease-in-out
877
+ hover:scale-110 active:scale-150
878
+ text-stone-800
879
+ hover:text-stone-950
880
+ active:text-black
881
+ group
 
 
 
 
882
  "
883
+ onClick={() => {
884
+ const randomStory = generateRandomStory()
885
+ setStoryPromptDraft(randomStory)
886
+ promptDraftRef.current = randomStory
887
+ }}>
888
+ <div>
889
+ </div>
890
+ <div className="
891
+ w-6 h-8
892
+ flex flex-row items-center justify-center
893
+ transition-all duration-150 ease-out
894
+ group-hover:animate-swing
895
+ "
896
+ >
897
+ <GiRollingDices size={24} />
898
+ </div>
899
  </div>
900
+ {/* END OF RANDOMNESS SWITCH */}
 
901
 
902
 
903
+ {/* ORIENTATION SWITCH */}
904
+ <div className="
905
+ flex flex-row
906
+ justify-between items-center
907
+ cursor-pointer
908
+ transition-all duration-150 ease-out
909
+ hover:scale-110 active:scale-150
910
+ text-stone-800
911
+ hover:text-stone-950
912
+ active:text-black
913
+ group
 
 
 
 
 
 
 
 
 
914
  "
915
+ onClick={() => toggleOrientation()}>
916
+ <div>
917
+ </div>
918
+ <div className="
919
+ w-8 h-8
920
+ flex flex-row items-center justify-center
921
+ transition-all duration-150 ease-in-out
922
+ group-hover:animate-swing
923
+ "
924
+ >
925
+ <div className={cn(
926
+ `transition-all duration-200 ease-in-out`,
927
+ orientation === ClapMediaOrientation.LANDSCAPE ? `rotate-90` : `rotate-0`
928
+ )}>
929
+ <IoMdPhonePortrait size={24} />
930
+ </div>
931
  </div>
932
  </div>
933
+ {/* END OF ORIENTATION SWITCH */}
934
+ <Button
935
+ onClick={handleSubmit}
936
+ disabled={!storyPromptDraft || isBusy}
937
+ // variant="ghost"
938
+ className={cn(
939
+ `text-base md:text-lg lg:text-xl xl:text-2xl`,
940
+ `bg-stone-800/90 text-amber-400/100 dark:bg-stone-800/90 dark:text-amber-400/100`,
941
+ `font-bold`,
942
+ `hover:bg-stone-800/100 hover:text-amber-300/100 dark:hover:bg-stone-800/100 dark:hover:text-amber-300/100`,
943
+ storyPromptDraft ? "opacity-100" : "opacity-80"
944
+ )}
945
+ >
946
+ <span className="mr-1.5">Create</span><span className="hidden md:inline">👉</span><span className="inline md:hidden">👇</span>
947
+ </Button>
948
  </div>
949
+
950
+ {/* END OF ACTION BAR */}
 
 
 
 
 
 
 
 
 
 
 
 
 
951
  </div>
952
 
953
+ </CardContent>
954
+ </Card>
955
+ </div>
956
+ <div className={cn(
957
+ `flex flex-col items-center justify-center`,
958
+ `flex-1 h-full`,
959
+ // `transition-all duration-200 ease-in-out`
960
 
961
+ `-mt-[20px] -mb-[90px] md:-mt-0 md:-mb-0`,
962
+ )}>
963
+
964
+ <div className={cn(`
965
+ -mt-8 md:mt-0
966
+ transition-all duration-200 ease-in-out
967
+ `,
968
+ isLandscape
969
+ ? `scale-[0.9] md:scale-[0.75] lg:scale-[0.9] xl:scale-[1.0] 2xl:scale-[1.1]`
970
+ : `scale-[0.8] md:scale-[0.9] lg:scale-[1.1]`
971
+ )}>
972
+ <DeviceFrameset
973
+ device="Nexus 5"
974
+ // color="black"
975
+
976
+ landscape={isLandscape}
977
+
978
+ // note 1: videos are generated in 1024x576 or 576x1024
979
+ // so we need to keep the same ratio here
980
+
981
+ // note 2: width and height are fixed, if width always stays 512
982
+ // that's because the landscape={} parameter will do the switch for us
983
+
984
+ width={288}
985
+ height={512}
986
+ >
987
+ <div className="
988
+ flex flex-col items-center justify-center
989
+ w-full h-full
990
+ bg-black text-white
991
+ ">
992
+ {isBusy ? <div className="
993
+ flex flex-col
994
+ items-center justify-center
995
+ text-center space-y-1.5">
996
+ <p className="text-2xl font-bold">{progress}%</p>
997
+ <p className="text-base text-white/70">{isBusy
998
+ ? (
999
+ // note: some of those tasks are running in parallel,
1000
+ // and some are super-slow (like music or video)
1001
+ // by carefully selecting in which order we set the ternaries,
1002
+ // we can create the illusion that we just have a succession of reasonably-sized tasks
1003
+ storyGenerationStatus === "generating" ? "Writing story.."
1004
+ : parseGenerationStatus === "generating" ? "Loading the project.."
1005
+ : assetGenerationStatus === "generating" ? "Casting characters.."
1006
+ : imageGenerationStatus === "generating" ? "Creating storyboards.."
1007
+ : soundGenerationStatus === "generating" ? "Recording sounds.."
1008
+ : videoGenerationStatus === "generating" ? "Filming shots.."
1009
+ : musicGenerationStatus === "generating" ? "Producing music.."
1010
+ : voiceGenerationStatus === "generating" ? "Recording dialogues.."
1011
+ : finalGenerationStatus === "generating" ? "Editing final cut.."
1012
+ : "Please wait.."
1013
+ )
1014
+ : status === "error"
1015
+ ? <span>{error || ""}</span>
1016
+ : <span>{error ? error : <span>&nbsp;</span>}</span> // to prevent layout changes
1017
+ }</p>
1018
+ </div>
1019
+ : (currentVideo && currentVideo?.length > 128) ? <video
1020
+ src={currentVideo}
1021
+ controls
1022
+ playsInline
1023
+ // I think we can't autoplay with sound,
1024
+ // so let's disable auto-play
1025
+ // autoPlay
1026
+ // muted
1027
+ loop
1028
+ className="object-cover"
1029
+ style={{
1030
+ }}
1031
+ /> : <div className="
1032
+ flex flex-col
1033
+ items-center justify-center
1034
+ text-lg text-center"></div>}
1035
+ </div>
1036
 
1037
+ <div className={cn(`
1038
+ fixed
1039
+ flex flex-row items-center justify-center
1040
+ bg-transparent
1041
+ font-sans
1042
+ -mb-0
1043
+ `,
1044
+ isLandscape ? 'h-4' : 'h-14'
1045
+ )}
1046
+ style={{ width: isPortrait ? 288 : 512 }}>
1047
+ <span className="text-stone-100/50 text-4xs"
1048
+ style={{ textShadow: "rgb(0 0 0 / 80%) 0px 0px 2px" }}>
1049
+ Powered by
1050
+ </span>
1051
+ <span className="ml-1 mr-0.5">
1052
+ <Image src={HFLogo} alt="Hugging Face" width={14} height={13} />
1053
+ </span>
1054
+ <span className="text-stone-100/80 text-3xs font-semibold"
1055
+ style={{ textShadow: "rgb(0 0 0 / 80%) 0px 0px 2px" }}>Hugging Face</span>
1056
+
1057
+ </div>
1058
+ </DeviceFrameset>
1059
+
1060
+ {(currentVideo && currentVideo.length > 128) ? <div
1061
+ className={cn(`
1062
+ w-full
1063
+ flex flex-row
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1064
  items-center justify-center
1065
+ transition-all duration-150 ease-in-out
1066
+
1067
+ text-stone-800
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1068
 
1069
+ group
1070
+ pt-2 md:pt-4
1071
+ `,
1072
+ isBusy ? 'opacity-50' : 'cursor-pointer opacity-100 hover:scale-110 active:scale-150 hover:text-stone-950 active:text-black'
1073
+ )}
1074
+ style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}
1075
+ onClick={isBusy ? undefined : saveVideo}
1076
+ >
1077
+ <div className="
1078
+ text-base md:text-lg lg:text-xl
1079
+ transition-all duration-150 ease-out
1080
+ group-hover:animate-swing
1081
+ "><FaCloudDownloadAlt /></div>
1082
+ <div className="text-xs md:text-sm lg:text-base">&nbsp;Download</div>
1083
+ </div> : null}
1084
+ </div>
1085
+ </div>
1086
+ </div>
1087
+ <div
1088
+ className="
1089
+ fixed
1090
+
1091
+ left-4 md:left-8
1092
+ bottom-4
1093
+ flex flex-col md:flex-row
1094
+ md:items-center justify-center
1095
+ space-y-4 md:space-x-4 md:space-y-0
1096
+
1097
+ ">
1098
+ <a
1099
+ className="
1100
+ flex
1101
+ no-underline
1102
+ animation-all duration-150 ease-in-out
1103
+ group
1104
+ text-stone-950/60 hover:text-stone-950/80 scale-95 hover:scale-100"
1105
+ href="https://discord.gg/AEruz9B92B"
1106
+ target="_blank">
1107
+ <div className="
1108
  text-base md:text-lg lg:text-xl
1109
  transition-all duration-150 ease-out
1110
  group-hover:animate-swing
1111
+ "><FaDiscord /></div>
1112
+ <div className="text-xs md:text-sm lg:text-base ml-1.5">
1113
+ <span className="hidden md:block">Chat on Discord</span>
1114
+ <span className="block md:hidden">Discord</span>
1115
+ </div>
1116
+ </a>
1117
+ <a
1118
+ className="
1119
+ flex
1120
+ no-underline
1121
+ animation-all duration-150 ease-in-out
1122
+ group
1123
+ text-stone-950/60 hover:text-stone-950/80 scale-95 hover:scale-100"
1124
+ href="https://latent-store.notion.site/AI-Stories-Academy-8e3ce6ff2d5946ffadc94193619dd5cd"
1125
+ target="_blank">
1126
+ <div className="
1127
+ text-base md:text-lg lg:text-xl
1128
+ transition-all duration-150 ease-out
1129
+ group-hover:animate-swing
1130
+ "><GiSpellBook /></div>
1131
+ <div className="text-xs md:text-sm lg:text-base ml-1.5">
1132
+ <span className="hidden md:block">Prompt academy</span>
1133
+ <span className="block md:hidden">Academy</span>
1134
+ </div>
1135
+ </a>
1136
  </div>
1137
  </div>
1138
+ <Toaster />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1139
  </div>
1140
+ </TooltipProvider>
 
1141
  );
1142
  }