diff --git a/.DS_Store b/.DS_Store index 04caf51..a75af8a 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/index.css b/index.css new file mode 100644 index 0000000..0c52521 --- /dev/null +++ b/index.css @@ -0,0 +1,1393 @@ +body { + font-family: 'Be Vietnam Pro', cursive; + transition: background-color 0.5s ease; + /* NEW: Add Polaroid theme variables */ + --polaroid-bg-color: #450A0A; + --polaroid-placeholder-color: #b45309; + --footer-bg-color: rgba(0, 0, 0, 0.8); +} + +.theme-sdvn { + background-color: #151523; + background-image: linear-gradient(to bottom, #5858e6, #151523); + /* OVERRIDE: Polaroid theme variables */ + --polaroid-bg-color: #1e1b4b; /* A deep indigo/purple */ + --polaroid-placeholder-color: #a5b4fc; /* A soft, light indigo */ + --footer-bg-color: rgba(30, 27, 75, 0.8); +} + +/* .theme-vietnam { + background-image: + url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3e%3cpath d='M50,5 L61.8,38.2 L98.2,38.2 L68.2,59.8 L79.6,92.7 L50,71.5 L20.4,92.7 L31.8,59.8 L1.8,38.2 L38.2,38.2 Z' fill='%23FFFF00' fill-opacity='0.15'/%3e%3c/svg%3e"), + radial-gradient(ellipse at bottom, #DA251D, #a21a14); + background-position: center, 0 0; + background-repeat: no-repeat, no-repeat; + background-size: 80vmin, cover; + background-attachment: fixed, fixed; + + --polaroid-bg-color: #450A0A; + --polaroid-placeholder-color: #b45309; + --footer-bg-color: rgba(69, 10, 10, 0.5); +} */ + +.theme-vietnam { + background-image: radial-gradient(ellipse at bottom, #c62921, #a21a14); + --polaroid-bg-color: #450A0A; /* bg-red-950 */ + --polaroid-placeholder-color: #b45309; /* text-yellow-700 */ + --footer-bg-color: rgba(69, 10, 10, 0.5); /* UPDATED: Increased transparency */ +} + +.theme-skyline { + background-color: #0052D4; /* Fallback color */ + background-image: linear-gradient(to left, #6FB1FC, #4364F7, #0052D4); + /* OVERRIDE: Polaroid theme variables */ + --polaroid-bg-color: #052e6c; /* A deep, rich blue */ + --polaroid-placeholder-color: #a7cffd; /* A soft, sky blue */ + --footer-bg-color: rgba(0, 82, 212, 0.5); /* UPDATED: Increased transparency */ +} + +/* NEW: Hidden Jaguar Theme */ +.theme-hidden-jaguar { + background-image: linear-gradient(to bottom, #0fd850 0%, #f9f047 100%); + --polaroid-bg-color: #14532d; + --polaroid-placeholder-color: #d9f99d; + --footer-bg-color: rgba(20, 83, 45, 0.6); +} + +/* NEW: Wide Matrix Theme */ +.theme-wide-matrix { + background-image: linear-gradient(to top, #fcc5e4 0%, #fda34b 15%, #ff7882 35%, #c8699e 52%, #7046aa 71%, #0c1db8 87%, #020f75 100%); + --polaroid-bg-color: #020f75; + --polaroid-placeholder-color: #fcc5e4; + --footer-bg-color: rgba(2, 15, 117, 0.6); +} + +/* === Additional Themes === */ +.theme-rainbow { + background-image: linear-gradient(to right, #0575E6, #00F260); + --polaroid-bg-color: #064e3b; + --polaroid-placeholder-color: #00F260; + --footer-bg-color: rgba(5, 150, 105, 0.6); +} + +.theme-soundcloud { + background-image: linear-gradient(to right, #f83600, #fe8c00); + --polaroid-bg-color: #7f1d1d; + --polaroid-placeholder-color: #fe8c00; + --footer-bg-color: rgba(127, 29, 29, 0.6); +} + +.theme-amin { + background-image: linear-gradient(to right, #4A00E0, #8E2DE2); + --polaroid-bg-color: #3b0764; + --polaroid-placeholder-color: #8E2DE2; + --footer-bg-color: rgba(59, 7, 100, 0.6); +} + + +.title-font { + font-family: 'Asimovian', sans-serif; +} + +/* .title-font { + font-family: 'Taviraj', serif; + font-weight: 300; + font-style: italic; +} */ +.sub-title-font { + font-family: 'Playwrite AU SA', cursive; +} +.base-font { + font-family: "Be Vietnam Pro", sans-serif; +} + +/* === NEW: Centralized Component Styles === */ + +/* --- Footer Theming --- */ +.footer-themed-bg { + background-color: var(--footer-bg-color); + transition: background-color 0.5s ease; +} + +/* --- NEW: Theme swatch styles --- */ +.theme-swatch { + width: 1rem; /* w-4 */ + height: 1rem; /* h-4 */ + border-radius: 9999px; /* rounded-full */ + border: 1px solid rgba(255, 255, 255, 0.3); + flex-shrink: 0; +} + +/* --- NEW: Custom Theme Dropdown styles --- */ +.theme-dropdown { + position: relative; +} + +.theme-dropdown-button { + display: inline-flex; + align-items: center; + gap: 0.5rem; /* gap-2 */ + background-color: rgba(0, 0, 0, 0.4); + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 0.5rem; /* rounded-lg - Increased radius */ + padding: 0.375rem 0.75rem; /* py-1.5 px-3 - Increased padding */ + color: #E5E5E5; /* text-neutral-200 */ + transition: background-color 150ms; + min-width: 150px; + justify-content: space-between; +} + +.theme-dropdown-button:hover { + background-color: rgba(0, 0, 0, 0.6); +} + +.theme-dropdown-button:focus { + outline: 2px solid transparent; + outline-offset: 2px; + box-shadow: 0 0 0 2px #FBBF24; /* focus:ring-2 focus:ring-yellow-400 */ +} + +.theme-dropdown-panel { + position: absolute; + bottom: 100%; /* position above the button */ + margin-bottom: 0.5rem; /* mb-2, space between button and panel */ + left: 0; + right: 0; + background-color: rgba(23, 23, 23, 0.95); /* bg-neutral-900 @ 95% */ + backdrop-filter: blur(12px); + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 0.75rem; /* rounded-xl - More rounded */ + z-index: 50; + list-style: none; + padding: 0.5rem; /* p-2 */ + max-height: 20rem; /* max-h-80 */ + overflow-y: auto; + box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5); /* Enhanced shadow */ +} + +/* Custom Scrollbar for Dropdown */ +.theme-dropdown-panel::-webkit-scrollbar { + width: 6px; +} +.theme-dropdown-panel::-webkit-scrollbar-track { + background: transparent; +} +.theme-dropdown-panel::-webkit-scrollbar-thumb { + background-color: #404040; /* neutral-700 */ + border-radius: 10px; +} + +.theme-dropdown-item { + display: flex; + align-items: center; + gap: 0.75rem; /* gap-3 */ + padding: 0.5rem 0.75rem; /* p-2 px-3 */ + cursor: pointer; + border-radius: 0.5rem; /* rounded-lg */ + color: #E5E5E5; /* text-neutral-200 */ + transition: background-color 150ms; + font-size: 0.875rem; +} + +.theme-dropdown-item:hover, .theme-dropdown-item[data-headlessui-state="active"] { + background-color: rgba(251, 191, 36, 0.2); /* bg-yellow-400/20 */ + color: #FBBF24; /* text-yellow-400 */ +} + + +/* --- Buttons --- */ +.btn { + font-family: "Be Vietnam Pro", sans-serif; + font-weight: 600; /* semibold */ + font-size: 1rem; /* text-base */ + text-align: center; + padding: 0.625rem 1.5rem; /* py-2.5 px-6 */ + border-radius: 0.5rem; /* rounded-lg */ + transition: transform 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease, color 0.2s ease; + -webkit-tap-highlight-color: transparent; /* Remove tap highlight on mobile */ +} + +.btn:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; +} + +.btn-primary { + color: #171717; /* neutral-900 */ + background-color: #FBBF24; /* bg-yellow-400 */ + border: 1px solid #FBBF24; + box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); /* shadow-sm */ +} +.btn-primary:hover:not(:disabled) { + transform: translateY(-2px); + background-color: #FCD34D; /* hover:bg-yellow-300 */ + border-color: #FCD34D; + box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); /* shadow-md */ +} +.btn-primary:disabled:hover { + background-color: #FBBF24; +} + +.btn-secondary { + color: #E5E5E5; /* text-neutral-200 */ + background-color: rgba(255, 255, 255, 0.1); + -webkit-backdrop-filter: blur(4px); /* backdrop-blur-sm */ + backdrop-filter: blur(4px); + border: 1px solid rgba(255, 255, 255, 0.2); + box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); +} +.btn-secondary:hover:not(:disabled) { + transform: translateY(-2px); + background-color: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.3); + box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); +} + +.btn-back { + z-index: 20; + display: flex; + align-items: center; + gap: 0.5rem; + color: white; + background-color: rgba(255, 255, 255, 0.1); + -webkit-backdrop-filter: blur(4px); /* backdrop-blur-sm */ + backdrop-filter: blur(4px); + border: 1px solid rgba(255, 255, 255, 0.2); + padding: 0.5rem 1rem; /* py-2 px-4 */ + border-radius: 9999px; /* rounded-full */ + font-size: 0.875rem; /* text-sm */ + transition-property: background-color; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.btn-back:hover { + background-color: rgba(255, 255, 255, 0.2); +} + +.btn-search { + z-index: 20; + display: flex; + align-items: center; + justify-content: center; + color: white; + background-color: rgba(255, 255, 255, 0.1); + -webkit-backdrop-filter: blur(4px); + backdrop-filter: blur(4px); + border: 1px solid rgba(255, 255, 255, 0.2); + width: 2.25rem; /* h-9, w-9 */ + height: 2.25rem; + padding: 0; + border-radius: 9999px; /* rounded-full */ + transition: background-color 150ms; +} + +.btn-search:hover:not(:disabled) { + background-color: rgba(255, 255, 255, 0.2); +} + +.btn-search:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; +} + +.btn-gallery { + z-index: 20; + display: flex; + align-items: center; + justify-content: center; + color: white; + background-color: rgba(255, 255, 255, 0.1); + -webkit-backdrop-filter: blur(4px); + backdrop-filter: blur(4px); + border: 1px solid rgba(255, 255, 255, 0.2); + width: 2.25rem; /* h-9, w-9 */ + height: 2.25rem; + padding: 0; + border-radius: 9999px; /* rounded-full */ + transition: background-color 150ms, opacity 150ms, transform 150ms; +} +.btn-gallery:hover:not(:disabled) { + background-color: rgba(255, 255, 255, 0.2); +} +.btn-gallery:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; +} + +.btn-sm { + padding: 0.5rem 1.25rem; /* py-2 px-5 */ + font-size: 0.875rem; /* text-sm */ +} + +/* --- Home Screen App Card --- */ +.app-card { + background-color: rgba(0, 0, 0, 0.2); + -webkit-backdrop-filter: blur(4px); /* backdrop-blur-sm */ + backdrop-filter: blur(4px); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 2rem; + cursor: pointer; + transition: all 300ms; + flex-basis: 100%; + max-width: 420px; + /* NEW styles */ + position: relative; + overflow: hidden; + aspect-ratio: 16 / 9; +} + + +@media(min-width: 640px) { /* sm breakpoint */ + .app-card { + flex-basis: calc(50% - 0.75rem); /* for 2 columns with 1.5rem gap */ + max-width: none; /* Remove max-width for multi-column layouts */ + } +} + +@media(min-width: 1024px) { /* lg breakpoint */ + .app-card { + flex-basis: calc(25% - 1.125rem); /* for 4 columns with 1.5rem gap */ + } +} + +.app-card:hover { + background-color: rgba(0, 0, 0, 0.4); + border-color: rgba(251, 191, 36, 0.5); /* hover:border-yellow-400/50 */ + transform: translateY(-0.5rem); /* hover:-translate-y-2 */ +} + +/* --- Forms (Selects, Textareas) --- */ +.form-input { + width: 100%; + padding: 0.75rem; /* p-3 */ + background-color: rgba(0, 0, 0, 0.2); + border: 1px solid rgba(255, 255, 255, 0.15); /* Increased border visibility */ + border-radius: 0.5rem; /* rounded-lg */ + color: #E5E5E5; /* text-neutral-200 */ + transition: all 150ms; +} + +.form-input:focus { + outline: 2px solid transparent; + outline-offset: 2px; + box-shadow: 0 0 0 2px #FBBF24; /* focus:ring-2 focus:ring-yellow-400 */ + background-color: rgba(0, 0, 0, 0.4); +} + +.form-input::placeholder { + color: #A3A3A3; /* placeholder-neutral-400 */ +} + +/* --- UPDATED: Custom Select Styling to fix white/white issue and visuals --- */ +select.form-input { + appearance: none; /* Remove default arrow */ + -webkit-appearance: none; + -moz-appearance: none; + background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a3a3a3' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right 0.75rem center; + background-size: 1rem; + padding-right: 2.5rem; /* Space for arrow */ + cursor: pointer; +} + +select.form-input option { + background-color: #171717; /* Dark background for options */ + color: #E5E5E5; /* Light text */ +} + +/* --- Polaroid Card --- */ +.polaroid-card { + background-color: #F5F5F5; /* bg-neutral-100 */ + padding: 1rem; /* !p-4 */ + padding-bottom: 4rem; /* !pb-16 */ + display: inline-flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + border-radius: 0.375rem; /* rounded-md */ + box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); /* shadow-lg */ + position: relative; +} + +.polaroid-image-container { + width: 100%; + background-color: var(--polaroid-bg-color); /* MODIFIED */ + box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05); /* shadow-inner */ + position: relative; + overflow: hidden; + transition: all 0.5s ease; + display: flex; + align-items: center; + justify-content: center; +} + +@media (min-width: 768px) { /* md */ + .polaroid-image-container { + height: 18rem; + width: auto; + } + .polaroid-image-container.has-image { + height: 27rem; /* 18rem * 1.5 */ + } +} + +/* Placeholder styles using CSS variables */ +.placeholder-icon-wrapper { + color: var(--polaroid-placeholder-color); + opacity: 0.4; + transition: opacity 0.3s ease, color 0.5s ease; +} + +.polaroid-image-container.group:hover .placeholder-icon-wrapper { + opacity: 0.6; +} + +.polaroid-caption { + font-family: 'Playwrite AU SA', cursive; + font-weight: 700; + font-size: 1.125rem; /* text-lg */ + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding-bottom: 0.25rem; /* pb-1 */ +} + +/* --- Modal --- */ +.modal-overlay { + position: fixed; + inset: 0; + background-color: rgba(0, 0, 0, 0.7); + z-index: 50; + display: flex; + align-items: center; + justify-content: center; + padding: 1rem; +} + +.modal-content { + background-color: rgba(38, 38, 38, 0.75); /* bg-neutral-800 @ 75% */ + -webkit-backdrop-filter: blur(12px); + backdrop-filter: blur(12px); + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 0.5rem; /* rounded-lg */ + box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); /* shadow-2xl */ + padding: 1.5rem; /* p-6 */ + width: 100%; + max-width: 32rem; /* max-w-lg */ + margin-left: auto; + margin-right: auto; + display: flex; + flex-direction: column; + gap: 1rem; /* gap-4 */ +} + +.modal-textarea { + width: 100%; + height: 7rem; /* h-28 */ + padding: 0.75rem; /* p-3 */ + background-color: #171717; /* bg-neutral-900 */ + border: 1px solid #404040; /* border-neutral-700 */ + border-radius: 0.375rem; /* rounded-md */ + color: #E5E5E5; /* text-neutral-200 */ + transition: box-shadow 150ms; +} +.modal-textarea:focus { + outline: 2px solid transparent; + outline-offset: 2px; + box-shadow: 0 0 0 2px #FBBF24; /* focus:ring-2 focus:ring-yellow-400 */ +} +.modal-textarea::placeholder { + color: #737373; /* placeholder-neutral-500 */ +} + +/* --- NEW: Prompt Result Card --- */ +/* This is a polaroid-style card specifically for displaying text content like prompts. */ +.prompt-card { + background-color: #F5F5F5; /* bg-neutral-100 */ + padding: 1rem; /* p-4 */ + border-radius: 0.375rem; /* rounded-md */ + box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); /* shadow-lg */ + + /* Flexbox setup to enable scrolling content */ + display: flex; + flex-direction: column; + position: relative; /* For the copy button */ + overflow: hidden; /* Crucial to contain the flex children and enable inner scroll */ + + /* Ensure it doesn't shrink and takes available width */ + width: 100%; +} + +/* The scrollable content area within the prompt card */ +.prompt-card-content { + flex: 1 1 0%; /* flex-1 */ + min-height: 0; /* Crucial for allowing shrinkage in flexbox */ + overflow-y: auto; /* Enable vertical scrollbar when content overflows */ + padding-right: 0.5rem; /* Add some padding so text doesn't touch the scrollbar */ + max-height:350px; +} + +/* Custom scrollbar styling for a cleaner look */ +.prompt-card-content::-webkit-scrollbar { + width: 8px; +} + +.prompt-card-content::-webkit-scrollbar-track { + background: transparent; /* Make the track invisible */ +} + +.prompt-card-content::-webkit-scrollbar-thumb { + background-color: #a3a3a3; /* neutral-400 */ + border-radius: 10px; + /* Add padding around the thumb to make it appear thinner */ + border: 2px solid #F5F5F5; /* Use card background color for padding */ +} + +.prompt-card-content::-webkit-scrollbar-thumb:hover { + background-color: #737373; /* neutral-500 */ +} + + +/* --- NEW: Results View Actions --- */ +.results-actions { + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + width: 100%; +} +.results-actions > * { /* Target buttons, etc. */ + width: 100%; +} + +@media(min-width: 640px) { /* sm breakpoint */ + .results-actions { + flex-direction: row; + flex-wrap: wrap; + justify-content: center; + width: auto; + padding: 0; + } + .results-actions > * { + width: auto; + max-width: none; + } +} +.results-actions > .btn { + padding: 0.375rem 1rem; /* py-1.5 px-4 */ + font-size: 0.875rem; /* text-sm */ + border-width: 1px; + box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); /* shadow-sm */ +} + +/* --- Pagination Controls --- */ +.pagination-nav { + display: flex; + align-items: center; + gap: 1rem; /* gap-4 */ + color: #D4D4D4; /* text-neutral-300 */ + font-family: "Be Vietnam Pro", sans-serif; + font-weight: 600; +} + +/* MODIFIED: Target only text buttons to avoid style conflicts with icon buttons */ +.pagination-nav button:not(.btn-search):not(.btn-gallery) { + color: white; + background-color: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(255, 255, 255, 0.2); + padding: 0.5rem 1rem; /* py-2 px-4 */ + border-radius: 9999px; /* rounded-full */ + font-size: 0.875rem; /* text-sm */ + font-weight: 600; + transition: background-color 150ms; +} + +.pagination-nav button:not(.btn-search):not(.btn-gallery):hover:not(:disabled) { + background-color: rgba(255, 255, 255, 0.2); +} + +.pagination-nav button:not(.btn-search):not(.btn-gallery):disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* --- UPDATED: Searchable Dropdown --- */ +.searchable-dropdown-container { + position: relative; + width: 100%; +} + +.searchable-dropdown-list { + position: absolute; + top: calc(100% + 0.5rem); /* Push down slightly */ + left: 0; + right: 0; + z-index: 60; /* Higher than standard input */ + background-color: rgba(23, 23, 23, 0.95); /* bg-neutral-900 @ 95% */ + -webkit-backdrop-filter: blur(12px); + backdrop-filter: blur(12px); + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 0.75rem; /* rounded-xl */ + max-height: 18rem; /* max-h-72 */ + overflow-y: auto; + list-style: none; + padding: 0.5rem; + box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.6); /* Stronger shadow */ +} + +/* Custom scrollbar for dropdown list */ +.searchable-dropdown-list::-webkit-scrollbar { + width: 6px; +} +.searchable-dropdown-list::-webkit-scrollbar-track { + background: transparent; +} +.searchable-dropdown-list::-webkit-scrollbar-thumb { + background-color: #404040; /* neutral-700 */ + border-radius: 10px; +} +.searchable-dropdown-list::-webkit-scrollbar-thumb:hover { + background-color: #525252; /* neutral-600 */ +} + + +.searchable-dropdown-item { + padding: 0.5rem 0.75rem; /* py-2 px-3 */ + cursor: pointer; + color: #E5E5E5; /* text-neutral-200 */ + transition: background-color 150ms, color 150ms; + border-radius: 0.5rem; /* rounded-lg */ + font-size: 0.875rem; + margin-bottom: 0.125rem; +} + +.searchable-dropdown-item:hover, .searchable-dropdown-item.is-highlighted { + background-color: rgba(251, 191, 36, 0.2); /* bg-yellow-400/20 */ + color: #FBBF24; /* text-yellow-400 */ +} + +/* --- NEW: Searchable Dropdown Group Header --- */ +.searchable-dropdown-group-header { + padding: 0.75rem 0.75rem 0.25rem; + font-size: 0.75rem; /* text-xs */ + font-weight: 700; + color: #a3a3a3; /* neutral-400 */ + text-transform: uppercase; + /* background-color: #1f1f1f; REMOVED: Let transparency work */ + position: sticky; + top: 0; + z-index: 1; /* Keep it above items when scrolling */ + pointer-events: none; +} + +/* --- NEW: Slider --- */ +.slider-container { + position: relative; + padding: 0.75rem 0; /* py-3 */ +} + +.slider-track { + -webkit-appearance: none; + appearance: none; + width: 100%; + height: 0.5rem; /* h-2 */ + background-color: rgba(0, 0, 0, 0.4); + border-radius: 9999px; /* rounded-full */ + outline: none; + transition: opacity 0.2s; + cursor: pointer; +} + +.slider-track::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 1rem; /* w-4 */ + height: 1rem; /* h-4 */ + background-color: #FBBF24; /* bg-yellow-400 */ + border-radius: 9999px; /* rounded-full */ + border: 2px solid #171717; /* border-neutral-900 */ + box-shadow: 0 0 0 1px #FBBF24; /* ring-1 ring-yellow-400 */ + cursor: pointer; + transition: transform 0.2s ease-in-out; +} +.slider-track::-webkit-slider-thumb:hover { + transform: scale(1.1); +} + +.slider-track::-moz-range-thumb { + width: 1rem; /* w-4 */ + height: 1rem; /* h-4 */ + background-color: #FBBF24; /* bg-yellow-400 */ + border-radius: 9999px; /* rounded-full */ + border: 2px solid #171717; /* border-neutral-900 */ + box-shadow: 0 0 0 1px #FBBF24; /* ring-1 ring-yellow-400 */ + cursor: pointer; + transition: transform 0.2s ease-in-out; +} +.slider-track::-moz-range-thumb:hover { + transform: scale(1.1); +} + + +.slider-labels { + display: flex; + justify-content: space-between; + margin-top: 0.75rem; /* mt-3 */ + padding: 0 0.5rem; /* px-2 to align with thumb edges */ +} + +.slider-label { + font-family: "Be Vietnam Pro", sans-serif; + font-size: 0.75rem; /* text-xs */ + color: #a3a3a3; /* text-neutral-400 */ + text-align: center; + flex: 1; + font-weight: 500; + transition: color 0.2s, font-weight 0.2s; +} + +.slider-label-active { + color: #FBBF24; /* text-yellow-400 */ + font-weight: 700; +} + +/* --- NEW: Gallery Modal (Pinterest Layout) --- */ +.gallery-grid { + flex-grow: 1; + overflow-y: auto; + column-count: 2; /* Default for mobile */ + column-gap: 0.75rem; /* gap-3 */ + padding: 0.25rem; +} +@media(min-width: 640px) { .gallery-grid { column-count: 3; } } +@media(min-width: 1024px) { .gallery-grid { column-count: 4; } } +@media(min-width: 1280px) { .gallery-grid { column-count: 5; } } + +.gallery-grid-item { + break-inside: avoid; + margin-bottom: 0.75rem; /* Vertical gap */ + border-radius: 0.25rem; /* rounded-sm */ + overflow: hidden; + cursor: pointer; + transition: transform 0.2s, box-shadow 0.2s; + position: relative; /* Needed for action buttons */ +} +.gallery-grid-item:hover { + transform: scale(1.02); + box-shadow: 0 0 10px rgba(251, 191, 36, 0.5); /* shadow-lg shadow-yellow-400/50 */ +} +.gallery-grid-item img, .gallery-grid-item video { + width: 100%; + height: auto; /* Allow natural aspect ratio */ + display: block; /* Remove any bottom space */ +} + +/* --- NEW: Gallery Thumbnail Actions --- */ +.thumbnail-actions { + position: absolute; + top: 0.5rem; /* top-2 */ + right: 0.5rem; /* right-2 */ + z-index: 10; + display: flex; + align-items: center; + gap: 0.5rem; /* gap-2 */ + opacity: 0; + transition-property: opacity, transform; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 200ms; + transform: translateY(0.25rem); /* Start slightly down */ +} + +.group:hover .thumbnail-actions { + opacity: 1; + transform: translateY(0); +} + +.thumbnail-action-btn { + padding: 0.5rem; /* p-2 */ + background-color: rgba(0, 0, 0, 0.6); + border-radius: 9999px; /* rounded-full */ + color: white; + transition: all 150ms; +} + +.thumbnail-action-btn:hover { + background-color: rgb(75 85 99); /* hover:bg-neutral-600 */ + transform: scale(1.1); +} + +.thumbnail-action-btn:focus { + outline: 2px solid transparent; + outline-offset: 2px; + box-shadow: 0 0 0 2px white; /* focus:ring-2 focus:ring-white */ +} + + +/* --- UPDATED: Gallery Lightbox --- */ +.gallery-lightbox { + position: fixed; + inset: 0; + z-index: 100; + display: flex; + align-items: center; + justify-content: center; +} +.gallery-lightbox-backdrop { + position: absolute; + inset: 0; + background-color: rgba(0,0,0,0.85); + -webkit-backdrop-filter: blur(8px); + backdrop-filter: blur(8px); + cursor: pointer; +} +.gallery-lightbox-img { + position: relative; + max-width: 90vw; + max-height: 85vh; + object-fit: contain; + border-radius: 0.5rem; /* rounded-lg */ + box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.5); /* shadow-2xl */ +} +.lightbox-action-btn { + position: absolute; + top: 0.75rem; + right: 0.75rem; + z-index: 120; + background-color: rgba(0, 0, 0, 0.5); + border: 1px solid rgba(255, 255, 255, 0.2); + color: white; + width: 2.5rem; + height: 2.5rem; + border-radius: 9999px; + display: flex; + align-items: center; + justify-content: center; + transition: background-color 0.2s, transform 0.2s; + cursor: pointer; +} +.lightbox-action-btn:hover { + background-color: rgba(0, 0, 0, 0.7); + transform: scale(1.1); +} + +/* --- NEW: Image Editor Modal --- */ +.image-editor-modal-content { + max-height: 100vh; +} + +.image-editor-preview-container { + display: flex; + justify-content: center; + align-items: center; + background-color: rgba(0,0,0,0.3); + border-radius: 0.25rem; + flex-grow: 1; + min-height: 0; +} + +.image-editor-preview { + max-width: 100%; + max-height: 100%; + object-fit: contain; + display: block; +} + +/* --- NEW: Before-After Modal --- */ +.comparison-container { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; + border-radius: 0.25rem; /* rounded-sm */ + user-select: none; +} +.comparison-image-wrapper { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; +} +.comparison-image { + width: 100%; + height: 100%; + object-fit: contain; + pointer-events: none; +} +.comparison-slider-handle { + position: absolute; + top: 0; + bottom: 0; + width: 1px; + background-color: rgba(255, 255, 255, 0.9); + cursor: ew-resize; + pointer-events: none; + transform: translateX(-50%); + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 0 5px rgba(0,0,0,0.3); +} +.comparison-slider-handle::after { + content: ''; + width: 28px; + height: 28px; + background-color: rgba(255, 255, 255, 0.9); + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 9999px; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='black' stroke-width='2.5'%3e%3cpath stroke-linecap='round' stroke-linejoin='round' d='M10 19l-7-7 7-7m4 14l7-7-7-7'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: center; + background-size: 65%; + box-shadow: 0 1px 3px rgba(0,0,0,0.2); +} +.comparison-range-input { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + -webkit-appearance: none; + appearance: none; + background: transparent; + cursor: ew-resize; + z-index: 10; +} +.comparison-range-input::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 40px; + height: 100%; + background: transparent; +} +.comparison-range-input::-moz-range-thumb { + width: 40px; + height: 100%; + background: transparent; + border: 0; + border-radius: 0; +} + +/* --- NEW: Before-After Modal Sidebar Grid --- */ +.before-after-sidebar-grid { + flex-grow: 1; + overflow-y: auto; + column-count: 1; /* Default for mobile */ + column-gap: 0.75rem; /* gap-3 */ + padding: 0.25rem; +} +@media(min-width: 640px) { .before-after-sidebar-grid { column-count: 2; } } + +/* --- NEW: Layer Composer Infinite Canvas Background --- */ +.infinite-canvas-bg { + background-color: #22252a; /* A dark, slightly blue-gray */ + background-image: + linear-gradient(rgba(255, 255, 255, 0.07) 1px, transparent 1px), + linear-gradient(90deg, rgba(255, 255, 255, 0.07) 1px, transparent 1px); + background-size: 20px 20px; +} + +/* --- NEW: AI Process Logger --- */ +.ai-process-logger { + position: fixed; + bottom: 4.5rem; /* Above footer */ + right: 1.5rem; + width: 100%; + max-width: 24rem; /* max-w-md */ + background-color: rgba(30, 30, 30, 0.8); + -webkit-backdrop-filter: blur(8px); + backdrop-filter: blur(8px); + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 0.75rem; /* rounded-xl */ + padding: 1rem; + z-index: 100; /* Above most other UI */ + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.ai-process-logger-header { + display: flex; + justify-content: space-between; + align-items: center; + padding-bottom: 0.5rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.ai-process-logger-title { + font-family: "Be Vietnam Pro", sans-serif; + font-weight: 700; + color: #FBBF24; /* text-yellow-400 */ +} + +.ai-process-logger-close { + padding: 0.25rem; + border-radius: 9999px; + color: #a3a3a3; /* neutral-400 */ + transition: background-color 0.2s; +} +.ai-process-logger-close:hover { + background-color: rgba(255, 255, 255, 0.1); + color: white; +} + +.ai-process-logger-content { + max-height: 15rem; /* max-h-60 */ + overflow-y: auto; + list-style-type: none; + padding: 0.5rem 0.25rem 0 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +/* Custom scrollbar for logger */ +.ai-process-logger-content::-webkit-scrollbar { + width: 6px; +} +.ai-process-logger-content::-webkit-scrollbar-track { + background: transparent; +} +.ai-process-logger-content::-webkit-scrollbar-thumb { + background-color: #737373; /* neutral-500 */ + border-radius: 10px; +} + +.ai-process-logger-item { + font-size: 0.875rem; /* text-sm */ + line-height: 1.4; +} + +.log-item-info { + color: #d4d4d4; /* neutral-300 */ +} + +.log-item-spinner { + color: #d4d4d4; /* neutral-300 */ + display: flex; + align-items: center; + gap: 0.5rem; +} + +.log-item-prompt { + background-color: rgba(0, 0, 0, 0.3); + padding: 0.75rem; + border-radius: 0.375rem; /* rounded-md */ + border: 1px solid rgba(255, 255, 255, 0.1); + color: #e5e5e5; /* neutral-200 */ + position: relative; +} + +.log-item-prompt pre { + white-space: pre-wrap; + word-break: break-word; + font-family: monospace; +} + +.log-item-prompt .copy-btn { + position: absolute; + top: 0.5rem; + right: 0.5rem; + padding: 0.25rem; + background-color: rgba(255, 255, 255, 0.1); + border-radius: 9999px; + color: #a3a3a3; /* neutral-400 */ + transition: all 0.2s; +} +.log-item-prompt .copy-btn:hover { + background-color: rgba(255, 255, 255, 0.2); + color: white; +} + +.log-item-success { + color: #4ade80; /* green-400 */ + font-weight: 600; +} + +.log-item-error { + color: #f87171; /* red-400 */ + font-weight: 600; +} + +/* --- NEW: Toggle Switch --- */ +.switch { + position: relative; + display: inline-block; + width: 40px; /* smaller width */ + height: 22px; /* smaller height */ +} + +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +.switch-slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #4b5563; /* gray-600 */ + transition: .4s; + border-radius: 22px; /* fully rounded */ +} + +.switch-slider:before { + position: absolute; + content: ""; + height: 16px; /* smaller knob */ + width: 16px; /* smaller knob */ + left: 3px; + bottom: 3px; + background-color: white; + transition: .4s; + border-radius: 50%; +} + +input:checked + .switch-slider { + background-color: #FBBF24; /* yellow-400 */ +} + +input:focus + .switch-slider { + box-shadow: 0 0 1px #FBBF24; +} + +input:checked + .switch-slider:before { + transform: translateX(18px); /* adjusted for new size */ +} + +/* --- NEW: Chatbot Markdown Styles --- */ +.chatbot-code-block { + position: relative; + background-color: #1a1a1a; + border-radius: 0.5rem; /* rounded-lg */ + border: 1px solid #333; + margin-top: 0.5rem; + margin-bottom: 0.5rem; + overflow: hidden; +} + +.chatbot-code-block .code-block-header { + display: flex; + justify-content: space-between; + align-items: center; + background-color: #2a2a2a; + padding: 0.25rem 0.75rem; + font-family: monospace; + font-size: 0.75rem; /* text-xs */ + color: #a3a3a3; /* neutral-400 */ +} + +.chatbot-code-block pre { + white-space: pre-wrap; + word-break: break-word; + font-family: monospace; + font-size: 0.875rem; /* text-sm */ + color: #e5e5e5; /* neutral-200 */ + padding: 0.75rem; +} + +.chatbot-code-block .copy-btn { + padding: 0.25rem; + border-radius: 9999px; /* rounded-full */ + color: #a3a3a3; /* neutral-400 */ + transition: all 0.2s; + cursor: pointer; +} + +.chatbot-code-block .copy-btn:hover { + background-color: rgba(255, 255, 255, 0.1); + color: white; +} + +/* Styles for comprehensive markdown */ +.chatbot-message > *:first-child { margin-top: 0; } +.chatbot-message > *:last-child { margin-bottom: 0; } +.chatbot-message p { margin-bottom: 0.5rem; } +.chatbot-message h1, +.chatbot-message h2, +.chatbot-message h3 { + font-weight: 700; + margin-top: 1rem; + margin-bottom: 0.5rem; + color: #FBBF24; /* yellow-400 */ +} +.chatbot-message h1 { font-size: 1.25em; } +.chatbot-message h2 { font-size: 1.1em; } +.chatbot-message h3 { font-size: 1.0em; } +.chatbot-message ul, +.chatbot-message ol { + margin-left: 0; + padding-left: 1.5rem; /* Indentation for lists */ + margin-bottom: 0.5rem; +} +.chatbot-message li { + margin-bottom: 0.25rem; +} +.chatbot-message blockquote { + border-left: 3px solid #737373; /* neutral-500 */ + padding-left: 1rem; + margin: 0.75rem 0; + color: #a3a3a3; /* neutral-400 */ + font-style: italic; +} +.chatbot-message a { + color: #FBBF24; /* yellow-400 */ + text-decoration: underline; + transition: color 0.2s; +} +.chatbot-message a:hover { + color: #FCD34D; /* yellow-300 */ +} +.chatbot-message hr { + border: 0; + border-top: 1px solid #404040; /* neutral-700 */ + margin: 1rem 0; +} + +/* NEW: Chatbot Send Button */ +.chatbot-send-btn { + position: absolute; + bottom: 0.75rem; /* 12px */ + right: 0.5rem; /* 8px */ + padding: 0.375rem; /* 6px */ + border-radius: 9999px; /* rounded-full */ + transition: all 150ms; + color: #a3a3a3; /* neutral-400 */ +} + +.chatbot-send-btn:not(:disabled) { + cursor: pointer; + color: #e5e5e5; /* neutral-200 */ +} + +.chatbot-send-btn:not(:disabled):hover { + background-color: rgba(251, 191, 36, 0.2); /* bg-yellow-400/20 */ + color: #FBBF24; /* text-yellow-400 */ +} + +.chatbot-send-btn:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +/* --- NEW: Results View Horizontal Scrollbar --- */ +.results-scroll-container::-webkit-scrollbar { + height: 12px; + width: 8px; +} + +.results-scroll-container::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.2); + border-radius: 10px; +} + +.results-scroll-container::-webkit-scrollbar-thumb { + background: rgba(251, 191, 36, 0.5); + border-radius: 10px; + border: 2px solid transparent; + background-clip: padding-box; +} + +.results-scroll-container::-webkit-scrollbar-thumb:hover { + background: rgba(251, 191, 36, 0.8); +} + +.results-scroll-container::-webkit-scrollbar:horizontal { + height: 12px; +} + +/* --- NEW: Storyboard Panel --- */ +.storyboard-panel { + display: flex; + flex-direction: column; + background-color: rgba(38, 38, 38, 0.7); /* neutral-800/70 */ + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 0.75rem; /* rounded-xl */ + overflow: hidden; + transition: box-shadow 0.2s; + min-height: 22.5rem; /* 360px */ +} +.storyboard-panel:hover { + box-shadow: 0 0 15px rgba(251, 191, 36, 0.2); +} +.storyboard-panel-image-container { + position: relative; + width: 100%; + background-color: #171717; /* neutral-900 */ + display: flex; + align-items: center; + justify-content: center; +} +.storyboard-panel-content { + padding: 0.75rem; /* p-3 */ + flex-grow: 1; + display: flex; + flex-direction: column; + min-height: 120px; /* Give it a minimum height */ +} +.storyboard-panel-description { + font-size: 0.75rem; /* text-xs */ + color: #d4d4d4; /* neutral-300 */ + overflow-y: auto; + padding-right: 0.25rem; + white-space: pre-wrap; + height: 120px; /* Fixed height */ +} +/* Custom scrollbar for description */ +.storyboard-panel-description::-webkit-scrollbar { width: 4px; } +.storyboard-panel-description::-webkit-scrollbar-track { background: transparent; } +.storyboard-panel-description::-webkit-scrollbar-thumb { background-color: #737373; border-radius: 4px; } + +.storyboard-panel-textarea { + width: 100%; + height: 90px; /* Fixed height */ + background-color: #171717; + border: 1px solid #404040; + border-radius: 0.375rem; + color: #e5e5e5; + font-size: 0.75rem; + padding: 0.5rem; + resize: none; +} +.storyboard-panel-textarea:focus { + outline: 2px solid transparent; + outline-offset: 2px; + box-shadow: 0 0 0 2px #FBBF24; +} + +.storyboard-panel-actions { + padding: 0 0.75rem 0.75rem; /* px-3 pb-3 */ +} + +/* --- NEW: Storyboard Scene Group --- */ +.storyboard-scene-group { + background-color: rgba(10, 10, 10, 0.2); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 1rem; /* rounded-2xl */ + padding: 0.5rem; /* p-2 */ + display: flex; + flex-direction: column; + gap: 1rem; /* gap-4 */ +} + +.storyboard-scene-group-title { + font-family: "Be Vietnam Pro", sans-serif; + font-weight: 700; /* bold */ + font-size: 1rem; /* text-lg */ + color: #FBBF24; /* text-yellow-400 */ + padding-bottom: 0.75rem; /* pb-3 */ + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + margin-bottom: 0.5rem; /* mb-2 */ +} diff --git a/static/script.js b/static/script.js index 157c895..c61fb20 100644 --- a/static/script.js +++ b/static/script.js @@ -75,7 +75,10 @@ document.addEventListener('DOMContentLoaded', () => { const promptInput = document.getElementById('prompt'); const promptNoteInput = document.getElementById('prompt-note'); const promptHighlight = document.getElementById('prompt-highlight'); + const noteHighlight = document.getElementById('note-highlight'); + const themeOptionsContainer = document.getElementById('theme-options'); const promptPlaceholderText = promptInput?.getAttribute('placeholder') || ''; + const promptNotePlaceholderText = promptNoteInput?.getAttribute('placeholder') || ''; const aspectRatioInput = document.getElementById('aspect-ratio'); const resolutionInput = document.getElementById('resolution'); const apiKeyInput = document.getElementById('api-key'); @@ -142,10 +145,11 @@ document.addEventListener('DOMContentLoaded', () => { if (settings.note) promptNoteInput.value = settings.note; if (settings.aspectRatio) aspectRatioInput.value = settings.aspectRatio; if (settings.resolution) resolutionInput.value = settings.resolution; - if (settings.model && apiModelSelect) { - apiModelSelect.value = settings.model; + if (apiModelSelect) { + apiModelSelect.value = settings.model || apiModelSelect.value || 'gemini-3-pro-image-preview'; toggleResolutionVisibility(); } + currentTheme = settings.theme || DEFAULT_THEME; return settings; } } catch (e) { @@ -155,8 +159,10 @@ document.addEventListener('DOMContentLoaded', () => { } function persistSettings() { - // Check if slotManager is initialized - const referenceImages = (typeof slotManager !== 'undefined') ? slotManager.getImages() : []; + // Safely collect cached reference images for restoration + const referenceImages = (typeof slotManager !== 'undefined' && typeof slotManager.serializeReferenceImages === 'function') + ? slotManager.serializeReferenceImages() + : []; const settings = { apiKey: apiKeyInput.value, @@ -165,7 +171,8 @@ document.addEventListener('DOMContentLoaded', () => { aspectRatio: aspectRatioInput.value, resolution: resolutionInput.value, model: apiModelSelect ? apiModelSelect.value : 'gemini-3-pro-image-preview', - referenceImages: referenceImages, + referenceImages, + theme: currentTheme || DEFAULT_THEME, }; try { localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings)); @@ -208,6 +215,22 @@ document.addEventListener('DOMContentLoaded', () => { '#a855f7', // purple ]; + const DEFAULT_THEME = 'theme-sdvn'; + + const themeOptionsData = [ + { id: 'theme-sdvn', name: 'SDVN', gradient: 'linear-gradient(to bottom, #5858e6, #151523)' }, + { id: 'theme-vietnam', name: 'Vietnam', gradient: 'radial-gradient(ellipse at bottom, #c62921, #a21a14)' }, + { id: 'theme-skyline', name: 'Skyline', gradient: 'linear-gradient(to left, #6FB1FC, #4364F7, #0052D4)' }, + { id: 'theme-hidden-jaguar', name: 'Hidden Jaguar', gradient: 'linear-gradient(to bottom, #0fd850 0%, #f9f047 100%)' }, + { id: 'theme-wide-matrix', name: 'Wide Matrix', gradient: 'linear-gradient(to top, #fcc5e4 0%, #fda34b 15%, #ff7882 35%, #c8699e 52%, #7046aa 71%, #0c1db8 87%, #020f75 100%)' }, + { id: 'theme-rainbow', name: 'Rainbow', gradient: 'linear-gradient(to right, #0575E6, #00F260)' }, + { id: 'theme-soundcloud', name: 'SoundCloud', gradient: 'linear-gradient(to right, #f83600, #fe8c00)' }, + { id: 'theme-amin', name: 'Amin', gradient: 'linear-gradient(to right, #4A00E0, #8E2DE2)' }, + ]; + + let currentPlaceholderSegments = []; + let currentTheme = DEFAULT_THEME; + function escapeHtml(value) { return value.replace(/[&<>"']/g, (char) => { switch (char) { @@ -224,6 +247,7 @@ document.addEventListener('DOMContentLoaded', () => { function buildPromptHighlightHtml(value) { if (!promptHighlight) return ''; if (!value) { + currentPlaceholderSegments = []; return `${escapeHtml(promptPlaceholderText)}`; } @@ -232,24 +256,100 @@ document.addEventListener('DOMContentLoaded', () => { let match; let colorIndex = 0; let html = ''; + const segments = []; while ((match = placeholderRegex.exec(value)) !== null) { html += escapeHtml(value.slice(lastIndex, match.index)); const color = promptHighlightColors[colorIndex % promptHighlightColors.length]; + segments.push({ + text: match[0], + color, + }); html += `${escapeHtml(match[0])}`; lastIndex = match.index + match[0].length; colorIndex++; } html += escapeHtml(value.slice(lastIndex)); + currentPlaceholderSegments = segments; return html || `${escapeHtml(promptPlaceholderText)}`; } + function buildNoteHighlightHtml(value) { + if (!noteHighlight) return ''; + if (!value) { + return `${escapeHtml(promptNotePlaceholderText)}`; + } + + const lines = value.split('\n'); + return lines + .map((line, index) => { + const color = currentPlaceholderSegments[index]?.color; + const styleAttr = color ? ` style="color:${color}"` : ''; + return `${escapeHtml(line)}`; + }) + .join('
'); + } + function refreshPromptHighlight() { if (!promptHighlight || !promptInput) return; promptHighlight.innerHTML = buildPromptHighlightHtml(promptInput.value); promptHighlight.scrollTop = promptInput.scrollTop; promptHighlight.scrollLeft = promptInput.scrollLeft; + refreshNoteHighlight(); + } + + function refreshNoteHighlight() { + if (!noteHighlight || !promptNoteInput) return; + noteHighlight.innerHTML = buildNoteHighlightHtml(promptNoteInput.value); + noteHighlight.scrollTop = promptNoteInput.scrollTop; + noteHighlight.scrollLeft = promptNoteInput.scrollLeft; + } + + function updateThemeSelectionUi() { + if (!themeOptionsContainer) return; + themeOptionsContainer.querySelectorAll('.theme-option').forEach(btn => { + const isActive = btn.dataset.themeId === currentTheme; + btn.classList.toggle('active', isActive); + btn.setAttribute('aria-selected', isActive); + }); + } + + function applyThemeClass(themeId) { + const themeIds = themeOptionsData.map(option => option.id); + document.body.classList.remove(...themeIds); + if (themeId && themeIds.includes(themeId)) { + document.body.classList.add(themeId); + currentTheme = themeId; + } else { + currentTheme = ''; + } + updateThemeSelectionUi(); + } + + function selectTheme(themeId, { persist = true } = {}) { + applyThemeClass(themeId); + if (persist) { + persistSettings(); + } + } + + function renderThemeOptions(initialTheme) { + if (!themeOptionsContainer) return; + themeOptionsContainer.innerHTML = ''; + themeOptionsData.forEach(option => { + const btn = document.createElement('button'); + btn.type = 'button'; + btn.className = 'theme-option'; + btn.dataset.themeId = option.id; + btn.setAttribute('role', 'option'); + btn.setAttribute('aria-label', `Chọn theme ${option.name}`); + btn.style.backgroundImage = option.gradient; + btn.innerHTML = `${option.name}`; + btn.addEventListener('click', () => selectTheme(option.id)); + themeOptionsContainer.appendChild(btn); + }); + applyThemeClass(initialTheme); } // --- End Helper Functions --- @@ -326,6 +426,8 @@ document.addEventListener('DOMContentLoaded', () => { }); const savedSettings = loadSettings(); + renderThemeOptions(currentTheme || DEFAULT_THEME); + applyThemeClass(currentTheme || DEFAULT_THEME); slotManager.initialize(savedSettings.referenceImages || []); refreshPromptHighlight(); @@ -359,9 +461,18 @@ document.addEventListener('DOMContentLoaded', () => { promptHighlight.scrollTop = promptInput.scrollTop; promptHighlight.scrollLeft = promptInput.scrollLeft; }); - promptNoteInput.addEventListener('input', persistSettings); + promptNoteInput.addEventListener('input', () => { + refreshNoteHighlight(); + persistSettings(); + }); + promptNoteInput.addEventListener('scroll', () => { + if (!noteHighlight) return; + noteHighlight.scrollTop = promptNoteInput.scrollTop; + noteHighlight.scrollLeft = promptNoteInput.scrollLeft; + }); aspectRatioInput.addEventListener('change', persistSettings); resolutionInput.addEventListener('change', persistSettings); + window.addEventListener('beforeunload', persistSettings); const queueCounter = document.getElementById('queue-counter'); const queueCountText = document.getElementById('queue-count-text'); diff --git a/static/style.css b/static/style.css index 13f92be..f0d56eb 100644 --- a/static/style.css +++ b/static/style.css @@ -1,7 +1,7 @@ :root { --bd-bg: radial-gradient(circle at 15% 20%, #2e2ce0 0%, #0b0b1b 35%, #03030b 100%); --panel-bg: rgba(10, 11, 22, 0.95); - --panel-backdrop: rgba(6, 7, 20, 0.7); + --panel-backdrop: rgba(6, 7, 20, 0.5); --border-color: rgba(255, 255, 255, 0.12); --text-primary: #f5f5f5; --text-secondary: #cbd5f5; @@ -402,6 +402,16 @@ textarea { min-height: 100px; } +/* Theme overrides driven from index.css gradients */ +body.theme-sdvn { --bd-bg: radial-gradient(circle at 15% 20%, #2e2ce0 0%, #0b0b1b 35%, #03030b 100%); } +body.theme-vietnam { --bd-bg: radial-gradient(ellipse at bottom, #c62921, #a21a14); } +body.theme-skyline { --bd-bg: linear-gradient(to left, #6FB1FC, #4364F7, #0052D4); } +body.theme-hidden-jaguar { --bd-bg: linear-gradient(to bottom, #0fd850 0%, #f9f047 100%); } +body.theme-wide-matrix { --bd-bg: linear-gradient(to top, #fcc5e4 0%, #fda34b 15%, #ff7882 35%, #c8699e 52%, #7046aa 71%, #0c1db8 87%, #020f75 100%); } +body.theme-rainbow { --bd-bg: linear-gradient(to right, #0575E6, #00F260); } +body.theme-soundcloud { --bd-bg: linear-gradient(to right, #f83600, #fe8c00); } +body.theme-amin { --bd-bg: linear-gradient(to right, #4A00E0, #8E2DE2); } + .prompt-wrapper { position: relative; width: 100%; @@ -414,7 +424,7 @@ textarea { .prompt-wrapper.prompt-highlighting { position: relative; border: 1px solid var(--border-color); - /* border-radius: 0.5rem; */ + border-radius: 0.5rem; /* background-color: var(--input-bg); */ backdrop-filter: blur(6px); overflow: hidden; @@ -467,10 +477,118 @@ textarea { font-size: 0.875rem; line-height: 1.4; resize: vertical; - min-height: 100px; + width: 100%; + height: 100%; opacity:0.3 } +.note-wrapper.note-highlighting { + position: relative; + border: 1px solid var(--border-color); + border-radius: 0.5rem; + /* background-color: var(--input-bg); */ + backdrop-filter: blur(6px); +} + +.note-highlight { + position: absolute; + inset: 0; + padding: 0.75rem; + overflow: auto; + pointer-events: none; + white-space: pre-wrap; + word-break: break-word; + z-index: 1; + color: var(--text-secondary); + font-family: inherit; + font-size: 0.875rem; + line-height: 1.4; +} + +.note-highlight::-webkit-scrollbar { + width: 0; + height: 0; +} + +.note-highlight .note-placeholder { + color: var(--text-secondary); +} + +.note-highlight .note-line { + display: inline; +} + +.note-wrapper.note-highlighting textarea { + position: relative; + z-index: 2; + border: none; + outline: none; + background: transparent; + color: transparent; + caret-color: var(--accent-color); + padding: 0.75rem; + font-family: inherit; + font-size: 0.875rem; + line-height: 1.4; + resize: vertical; + opacity: 0.3; + width: 100%; + height: 100%; +} + +.theme-option-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); + gap: 0.4rem; +} + +.theme-option { + position: relative; + border: 1px solid rgba(255, 255, 255, 0.18); + border-radius: 1rem; + padding: 0.6rem; + color: #fff; + cursor: pointer; + transition: transform 0.15s ease, border-color 0.2s ease, box-shadow 0.2s ease, background-position 0.4s ease; + text-align: left; + height: 40px; + overflow: hidden; +} + +.theme-option::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(to top right, rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.05)); + pointer-events: none; +} + +.theme-option .theme-option-name { + position: relative; + z-index: 1; + font-weight: 700; + letter-spacing: 0.3px; + font-size: 0.85rem; + text-shadow: 0 1px 6px rgba(0, 0, 0, 0.35); +} + +.theme-option:focus-visible { + outline: 2px solid var(--accent-color); + outline-offset: 2px; +} + +.theme-option:hover { + transform: translateY(-1px); + border-color: var(--accent-color); + box-shadow: 0 12px 24px rgba(0, 0, 0, 0.45); + background-position: 80% 20%; +} + +.theme-option.active { + border-color: var(--accent-color); + box-shadow: 0 0 0 1px rgba(251, 191, 36, 0.5), 0 12px 28px rgba(251, 191, 36, 0.18); +} + .prompt-actions { display: flex; justify-content: flex-end; @@ -709,7 +827,7 @@ button#generate-btn:disabled { padding: 2rem; overflow: hidden; position: relative; - background: radial-gradient(circle at top, rgba(27, 38, 102, 0.4), rgba(6, 6, 18, 0.95)); + background: var(--panel-backdrop); border-radius: 1.5rem; cursor: grab; user-select: none; @@ -930,7 +1048,7 @@ button#generate-btn:disabled { height: 180px; flex-shrink: 0; width: 100%; - background: transparent; + background: var(--panel-backdrop); } .history-section h3 { diff --git a/templates/index.html b/templates/index.html index 0ee4943..19808d8 100644 --- a/templates/index.html +++ b/templates/index.html @@ -90,8 +90,11 @@
- +
+ + +
@@ -381,7 +384,7 @@ aria-labelledby="api-settings-title"> +
+ +
+