Yohji commited on
Commit
4bfdb8f
·
verified ·
1 Parent(s): 7d0ba97

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +299 -1
index.html CHANGED
@@ -495,4 +495,302 @@
495
  <div className="p-4 border-b border-gray-100 flex justify-between items-center bg-white relative">
496
  <h2 className="font-bold text-sm uppercase text-gray-500">Deal Inventory</h2>
497
  <div className="flex gap-2">
498
- <button onClick={()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
495
  <div className="p-4 border-b border-gray-100 flex justify-between items-center bg-white relative">
496
  <h2 className="font-bold text-sm uppercase text-gray-500">Deal Inventory</h2>
497
  <div className="flex gap-2">
498
+ <button onClick={() => setDeals(generateSampleData())} className="text-xs bg-gray-100 border border-gray-200 px-3 py-1.5 rounded hover:bg-gray-200 transition-colors">Reset Demo</button>
499
+
500
+ {/* IMPORT DROPDOWN */}
501
+ <div className="relative">
502
+ <button
503
+ onClick={() => setShowImportMenu(!showImportMenu)}
504
+ className="text-xs bg-cyan-50 text-cyan-700 border border-cyan-100 px-3 py-1.5 rounded hover:bg-cyan-100 flex items-center gap-1 transition-colors"
505
+ >
506
+ <Upload size={12} /> Import <ChevronDown size={10} />
507
+ </button>
508
+
509
+ {showImportMenu && (
510
+ <div className="absolute right-0 top-full mt-1 w-48 bg-white border border-gray-200 rounded-lg shadow-xl z-40 py-1 flex flex-col animate-in fade-in slide-in-from-top-2">
511
+ <button
512
+ onClick={openLinkModal}
513
+ className="text-left px-4 py-2 hover:bg-gray-50 text-xs font-medium text-gray-700 flex items-center gap-2 w-full"
514
+ >
515
+ <LinkIcon size={14} className="text-blue-500" /> From Link / Cloud
516
+ </button>
517
+ <label className="text-left px-4 py-2 hover:bg-gray-50 text-xs font-medium text-gray-700 flex items-center gap-2 cursor-pointer w-full">
518
+ <FileImage size={14} className="text-green-500"/> From Screenshot
519
+ <input type="file" className="hidden" onChange={handleFileUpload} accept=".json,.jpg,.png,.xlsx" />
520
+ </label>
521
+ </div>
522
+ )}
523
+ </div>
524
+ </div>
525
+ </div>
526
+
527
+ {/* TABS */}
528
+ <div className="flex border-b border-gray-200">
529
+ <button
530
+ onClick={() => setActiveTab('weekend')}
531
+ className={`flex-1 py-3 text-xs font-bold uppercase tracking-wider border-b-2 transition-colors ${activeTab === 'weekend' ? 'border-cyan-500 text-cyan-600 bg-cyan-50' : 'border-transparent text-gray-400 hover:text-gray-600'}`}
532
+ >
533
+ Weekend
534
+ </button>
535
+ <button
536
+ onClick={() => setActiveTab('weekday')}
537
+ className={`flex-1 py-3 text-xs font-bold uppercase tracking-wider border-b-2 transition-colors ${activeTab === 'weekday' ? 'border-pink-500 text-pink-600 bg-pink-50' : 'border-transparent text-gray-400 hover:text-gray-600'}`}
538
+ >
539
+ Weekday
540
+ </button>
541
+ <button
542
+ onClick={() => setActiveTab('footer')}
543
+ className={`flex-1 py-3 text-xs font-bold uppercase tracking-wider border-b-2 transition-colors ${activeTab === 'footer' ? 'border-yellow-500 text-yellow-700 bg-yellow-50' : 'border-transparent text-gray-400 hover:text-gray-600'}`}
544
+ >
545
+ Footer
546
+ </button>
547
+ </div>
548
+
549
+ {/* LIST */}
550
+ <div className={`flex-1 overflow-y-auto p-4 space-y-3 ${activeTab === 'weekend' ? 'bg-cyan-50/30' : activeTab === 'weekday' ? 'bg-pink-50/30' : 'bg-yellow-50/30'}`} ref={inventoryListRef}>
551
+ {inventoryDeals.length === 0 && (
552
+ <div className="text-center py-8 text-gray-400 text-xs italic">No deals in this section.</div>
553
+ )}
554
+ {inventoryDeals.map((deal) => (
555
+ <div key={deal.id} className="bg-white border border-gray-200 p-3 rounded-lg shadow-sm hover:shadow-md transition-all group relative">
556
+ <div className="flex justify-between items-center mb-2">
557
+ <span className={`text-[10px] font-bold px-2 py-0.5 rounded uppercase ${
558
+ deal.type === 'weekend' ? 'bg-cyan-100 text-cyan-800' :
559
+ deal.type === 'weekday' ? 'bg-pink-100 text-pink-800' :
560
+ 'bg-yellow-100 text-yellow-800'
561
+ }`}>
562
+ {deal.type}
563
+ </span>
564
+ <div className="flex gap-2">
565
+ <button onClick={() => deleteDeal(deal.id)} className="text-gray-300 hover:text-red-500 transition-colors"><Trash2 size={14} /></button>
566
+ </div>
567
+ </div>
568
+
569
+ {deal.type === 'footer' ? (
570
+ <div className="space-y-2">
571
+ <div className="flex items-center gap-2">
572
+ <label className="flex-1 flex items-center justify-center gap-2 p-2 border border-dashed border-gray-300 rounded hover:bg-yellow-50 cursor-pointer group transition-colors bg-gray-50">
573
+ <ImageIcon size={14} className="text-gray-400 group-hover:text-yellow-600"/>
574
+ <span className="text-[10px] font-bold text-gray-500 group-hover:text-yellow-700 uppercase">
575
+ {deal.footerLogo ? 'Change Logo' : 'Brand Logo'}
576
+ </span>
577
+ <input type="file" className="hidden" onChange={(e) => handleFooterLogoUpload(deal.id, e)} accept="image/*"/>
578
+ </label>
579
+ {deal.footerLogo && (
580
+ <div className="w-9 h-9 rounded bg-white flex items-center justify-center border border-gray-200 shrink-0">
581
+ <img src={deal.footerLogo} alt="Brand" className="w-7 h-7 object-contain" />
582
+ </div>
583
+ )}
584
+ </div>
585
+ <div className="grid grid-cols-2 gap-2">
586
+ <textarea rows={2} value={deal.footerSplitLeft || ''} onChange={(e) => updateDeal(deal.id, 'footerSplitLeft', e.target.value)} placeholder="Left Text" className="text-xs border border-gray-200 rounded p-2 w-full font-mono bg-gray-50 focus:bg-white focus:border-yellow-400 outline-none" />
587
+ <textarea rows={2} value={deal.footerSplitRight || ''} onChange={(e) => updateDeal(deal.id, 'footerSplitRight', e.target.value)} placeholder="Right Text" className="text-xs border border-gray-200 rounded p-2 w-full font-mono bg-gray-50 focus:bg-white focus:border-yellow-400 outline-none" />
588
+ </div>
589
+ </div>
590
+ ) : (
591
+ <div className="grid grid-cols-[1fr_80px] gap-2">
592
+ <div>
593
+ <input type="text" value={deal.brand} onChange={(e) => updateDeal(deal.id, 'brand', e.target.value)} className="w-full font-bold text-sm border-b border-gray-100 focus:border-cyan-500 outline-none pb-1 mb-1 bg-transparent" placeholder="Brand Name" />
594
+ <div className="flex gap-2 items-center">
595
+ <input type="text" value={deal.notes || ''} onChange={(e) => updateDeal(deal.id, 'notes', e.target.value)} className="flex-1 text-[10px] text-gray-500 border-b border-gray-100 focus:border-cyan-500 outline-none bg-transparent" placeholder="Notes/Exclusions" />
596
+ <select value={deal.product} onChange={(e) => updateDeal(deal.id, 'product', e.target.value)} className="w-[90px] text-[9px] font-bold text-gray-600 bg-gray-50 border border-gray-200 rounded p-1 focus:border-cyan-500 outline-none">
597
+ {CATEGORIES.map(cat => (<option key={cat} value={cat}>{cat}</option>))}
598
+ </select>
599
+ </div>
600
+ </div>
601
+ <input type="text" value={deal.discount} onChange={(e) => updateDeal(deal.id, 'discount', e.target.value)} className="text-right font-bold text-red-500 border-b border-gray-100 focus:border-red-500 outline-none h-8 self-start bg-transparent" placeholder="30% OFF" />
602
+ </div>
603
+ )}
604
+ </div>
605
+ ))}
606
+ <button onClick={addDeal} className="w-full py-4 border-2 border-dashed border-gray-300 text-gray-400 rounded-lg hover:border-cyan-400 hover:text-cyan-600 hover:bg-white transition-all text-sm font-bold flex items-center justify-center gap-2 uppercase tracking-wide bg-transparent">
607
+ <Plus size={16} /> Add {activeTab} Deal
608
+ </button>
609
+ </div>
610
+ </div>
611
+
612
+ {/* PREVIEW PANEL (Right) */}
613
+ <div className={`flex-1 bg-gray-200 flex flex-col overflow-hidden transition-all duration-300 ${showInventory ? 'ml-[420px]' : 'ml-0'}`}>
614
+
615
+ {/* Size Tabs */}
616
+ <div className="h-12 bg-white border-b border-gray-200 flex items-center px-4 gap-2 overflow-x-auto no-scrollbar">
617
+ {OUTPUT_SIZES.map((size) => (
618
+ <button
619
+ key={size.id}
620
+ onClick={() => setSelectedSize(size)}
621
+ className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-xs font-bold whitespace-nowrap transition-all border ${
622
+ selectedSize.name === size.name
623
+ ? 'bg-slate-800 text-white border-slate-800'
624
+ : 'bg-white text-slate-600 border-gray-200 hover:border-gray-400'
625
+ }`}
626
+ >
627
+ {size.icon}
628
+ {size.name} <span className="opacity-50 text-[9px] ml-1 font-normal">({size.width}x{size.height})</span>
629
+ </button>
630
+ ))}
631
+ </div>
632
+
633
+ {/* Canvas Area */}
634
+ <div className="flex-1 flex items-center justify-center overflow-hidden bg-slate-200/50 p-8" ref={containerRef}>
635
+ <div
636
+ ref={posterRef}
637
+ id="poster-container"
638
+ style={{
639
+ width: `${selectedSize.width}px`,
640
+ height: `${selectedSize.height}px`,
641
+ transform: `scale(${scale})`,
642
+ transformOrigin: 'center',
643
+ boxShadow: '0 30px 80px -20px rgba(0, 0, 0, 0.3)'
644
+ }}
645
+ className="bg-white relative flex flex-col select-none overflow-hidden shrink-0 transition-all duration-500 ease-out"
646
+ >
647
+ {/* --- POSTER CONTENT START --- */}
648
+
649
+ {/* HEADER */}
650
+ <div className={`${isPortrait ? 'h-[7%]' : 'h-[10%]'} bg-black flex items-center justify-between px-[3%] shrink-0 z-10`}>
651
+ <div className="flex items-center gap-[2%] h-full overflow-hidden flex-1">
652
+ <div className="h-full flex items-center shrink-0">
653
+ <h1 className={`${isPortrait ? 'text-[3em]' : 'text-[4em]'} font-black text-white tracking-tight italic uppercase leading-none font-stencil transform scale-y-110`} style={{ fontFamily: 'Black Ops One, cursive' }}>CULTURE</h1>
654
+ </div>
655
+ <div className="h-[40%] w-0.5 bg-gray-600 shrink-0"></div>
656
+ <div className="flex flex-col justify-center min-w-0 flex-1">
657
+ <h2 className={`${isPortrait ? 'text-[1.5em]' : 'text-[2.5em]'} font-bold text-white uppercase tracking-wide leading-none truncate`}>{locationName} WEEKLY DEALS</h2>
658
+ <p className={`${isPortrait ? 'text-[0.6em]' : 'text-[0.8em]'} text-gray-400 uppercase tracking-widest mt-[1%] truncate w-full`}>WE PRICE MATCH ALL PRODUCTS</p>
659
+ </div>
660
+ </div>
661
+ <input
662
+ type="text"
663
+ value={dateRange}
664
+ onChange={(e) => setDateRange(e.target.value)}
665
+ className={`${isPortrait ? 'text-[2.2em]' : 'text-[3.2em]'} font-bold text-yellow-400 tracking-wide leading-none shrink-0 pl-4 bg-transparent border-none outline-none text-right w-[40%] uppercase placeholder:text-yellow-400/50`}
666
+ placeholder="NOV 17 - NOV 23"
667
+ />
668
+ </div>
669
+
670
+ {/* BODY CONTAINER */}
671
+ <div className={`flex-1 bg-[#4a4a4a] m-[2%] rounded-[30px] p-[2%] flex flex-col gap-[2%] relative shadow-inner overflow-hidden`}>
672
+
673
+ {/* TOP SECTION */}
674
+ <div className={`flex ${isPortrait ? 'flex-col gap-[2%]' : 'flex-row gap-[2%]'} flex-1 min-h-0`}>
675
+
676
+ {/* WEEKEND SECTION */}
677
+ <div className={`${isPortrait ? 'w-full h-[50%]' : 'w-[60%] h-full'} flex flex-col`}>
678
+ <div className="h-[15%] bg-[#00c2cb] rounded-t-2xl flex items-center px-[4%] justify-between shrink-0 shadow-md">
679
+ <span className="text-[2.5em] font-bold text-white uppercase tracking-wide truncate">WEEKEND DEALS</span>
680
+ <div className="bg-white text-[#00c2cb] px-[3%] py-[0.5%] rounded-full text-[1em] font-black uppercase shrink-0">FRI - SUN</div>
681
+ </div>
682
+ <div className="flex-1 bg-[#4a4a4a] py-[2%] flex flex-col gap-[2%] overflow-hidden">
683
+ {weekendDeals.map((deal) => (
684
+ <div key={deal.id} className="bg-white rounded-full flex-1 w-full flex items-center px-[3%] justify-between shadow-sm shrink-0 overflow-hidden min-h-0">
685
+ <div className="flex items-baseline gap-[3%] overflow-hidden flex-1 pr-[2%] min-w-0">
686
+ <span className="text-[1.5em] font-black text-black uppercase truncate">{deal.brand}</span>
687
+ <span className="text-[0.8em] font-bold text-gray-500 uppercase truncate flex-shrink-1 min-w-0">{deal.notes}</span>
688
+ </div>
689
+ <div className="bg-[#ef3e42] text-white px-[2%] w-[30%] h-[80%] rounded-full font-black text-[1.6em] italic flex items-center justify-center transform skew-x-[-10deg] shrink-0 shadow-sm">
690
+ <div className="transform skew-x-[10deg] truncate w-full text-center">{deal.discount}</div>
691
+ </div>
692
+ </div>
693
+ ))}
694
+ </div>
695
+ </div>
696
+
697
+ {/* WEEKDAY SECTION */}
698
+ <div className={`${isPortrait ? 'w-full h-[50%]' : 'w-[40%] h-full'} flex flex-col`}>
699
+ <div className="h-[15%] bg-[#ff4081] rounded-t-2xl flex items-center px-[4%] justify-between shrink-0 shadow-md">
700
+ <span className="text-[2.5em] font-bold text-white uppercase tracking-wide truncate">WEEKDAY</span>
701
+ <div className="bg-white text-[#ff4081] px-[3%] py-[0.5%] rounded-full text-[1em] font-black uppercase shrink-0">MON-THU</div>
702
+ </div>
703
+ <div className="flex-1 py-[2%] flex flex-wrap content-stretch gap-[2%] overflow-hidden">
704
+ {weekdayDeals.map((deal, idx) => {
705
+ const isLastItem = idx === weekdayDeals.length - 1;
706
+ const isOddCount = weekdayDeals.length % 2 !== 0;
707
+ return (
708
+ <div
709
+ key={deal.id}
710
+ className={`bg-gradient-to-b from-white to-pink-50 rounded-xl px-[8%] py-[6%] relative shadow-sm flex flex-col justify-between overflow-hidden flex-grow shrink-0 ${isLastItem && isOddCount ? 'basis-[100%]' : 'basis-[48%]'} min-h-0`}
711
+ >
712
+ <div className="flex flex-col w-full min-w-0">
713
+ <span className="text-[1.2em] font-black text-[#d81b60] uppercase leading-none truncate w-full">{deal.brand}</span>
714
+ <span className="text-[0.9em] font-bold text-black uppercase leading-tight truncate w-full mt-[2%]">{deal.product}</span>
715
+ {deal.notes && <span className="text-[0.6em] text-gray-500 uppercase mt-[2%] leading-none truncate w-full">{deal.notes}</span>}
716
+ </div>
717
+ <div className="self-end bg-[#ef3e42] text-white w-auto min-w-[45%] h-[2.4em] px-[0.5em] rounded-lg font-black text-[1.6em] shadow-md flex items-center justify-center leading-none truncate">
718
+ {deal.discount}
719
+ </div>
720
+ </div>
721
+ );
722
+ })}
723
+ </div>
724
+ </div>
725
+ </div>
726
+
727
+ {/* FOOTER SECTION */}
728
+ <div className={`${isPortrait ? 'h-[12%] mt-auto' : 'h-[25%]'} flex gap-[2%] shrink-0 w-full min-h-0`}>
729
+ {footerDeals.map((deal, idx) => {
730
+ const isSingleItem = !deal.footerSplitRight;
731
+ return (
732
+ <div key={deal.id} className="rounded-2xl overflow-hidden flex flex-col bg-black shadow-lg h-full min-h-0 flex-1">
733
+ <div className="h-[25%] w-full bg-[#ffeb3b] shrink-0 flex items-center justify-center px-[5%] overflow-hidden">
734
+ {deal.footerLogo ? (
735
+ <img src={deal.footerLogo} alt="Brand" className="h-[80%] w-auto object-contain" />
736
+ ) : (
737
+ <span className="text-[0.7em] font-bold text-yellow-800/30 uppercase tracking-widest">Premium Spot</span>
738
+ )}
739
+ </div>
740
+ <div className="flex-1 flex items-center justify-center px-[5%] text-center overflow-hidden min-w-0">
741
+ {isSingleItem ? (
742
+ <div className="flex flex-col items-center w-full min-w-0 py-[5%]">
743
+ <pre className="font-black text-white text-[1.4em] uppercase leading-tight font-sans whitespace-pre-wrap overflow-hidden text-ellipsis w-full px-1">{deal.footerSplitLeft || deal.brand}</pre>
744
+ <div className="text-[0.8em] text-gray-400 uppercase mt-[2%] truncate w-full px-1">{deal.notes}</div>
745
+ </div>
746
+ ) : (
747
+ <div className="flex w-full h-full items-center">
748
+ <div className="flex-1 border-r border-gray-700 h-[80%] flex items-center justify-center overflow-hidden min-w-0 px-1 py-[5%]">
749
+ <pre className="font-black text-white text-[1.2em] uppercase leading-none font-sans whitespace-pre-wrap text-center w-full overflow-hidden text-ellipsis">{deal.footerSplitLeft}</pre>
750
+ </div>
751
+ <div className="flex-1 flex items-center justify-center overflow-hidden h-[80%] min-w-0 px-1 py-[5%]">
752
+ <pre className="font-black text-white text-[1.2em] uppercase leading-none font-sans whitespace-pre-wrap text-center w-full overflow-hidden text-ellipsis">{deal.footerSplitRight}</pre>
753
+ </div>
754
+ </div>
755
+ )}
756
+ </div>
757
+ <div className="bg-gray-900 text-gray-500 text-[0.6em] text-center py-[1%] uppercase font-bold shrink-0">
758
+ NOVEMBER 2025
759
+ </div>
760
+ </div>
761
+ );
762
+ })}
763
+ </div>
764
+
765
+ {/* LEGEND STRIP */}
766
+ <div className="absolute bottom-[1%] left-[2%] right-[2%] flex justify-between items-center text-[0.7em] text-gray-400 uppercase font-bold tracking-wider h-[2%] shrink-0 overflow-hidden">
767
+ <div className="flex gap-[2%] items-center">
768
+ <span className="whitespace-nowrap">CATEGORY LEGEND:</span>
769
+ <div className="flex items-center gap-[0.2em] whitespace-nowrap"><Circle size={'1em'}/> ALL PRODUCTS</div>
770
+ <div className="flex items-center gap-[0.2em] whitespace-nowrap"><Pill size={'1em'}/> PREROLLS</div>
771
+ <div className="flex items-center gap-[0.2em] whitespace-nowrap"><Disc size={'1em'}/> VAPES</div>
772
+ <div className="flex items-center gap-[0.2em] whitespace-nowrap"><Type size={'1em'}/> FLOWERS</div>
773
+ <div className="flex items-center gap-[0.2em] whitespace-nowrap"><Droplet size={'1em'}/> EXTRACTS</div>
774
+ <div className="flex items-center gap-[0.2em] whitespace-nowrap"><Coffee size={'1em'}/> EDIBLES</div>
775
+ <div className="flex items-center gap-[0.2em] whitespace-nowrap"><Wine size={'1em'}/> BEVERAGES</div>
776
+ <div className="flex items-center gap-[0.2em] whitespace-nowrap"><Briefcase size={'1em'}/> WELLNESS</div>
777
+ </div>
778
+ <div className="text-right leading-tight min-w-0 hidden lg:block">
779
+ <div className="text-white truncate">*DEALS AVAILABLE AT {locationName}</div>
780
+ </div>
781
+ </div>
782
+
783
+ </div>
784
+ </div>
785
+ </div>
786
+ </div>
787
+ </div>
788
+ </div>
789
+ );
790
+ };
791
+
792
+ const root = ReactDOM.createRoot(document.getElementById('root'));
793
+ root.render(<DealCardMaker />);
794
+ </script>
795
+ </body>
796
+ </html>