Spaces:
Running
Running
analyze fix upgrade, prioritize mvp top 3 e2e tested n functional simple but valuable human struggle time minimizers
3e519ec verified | class ToolDecider extends HTMLElement { | |
| connectedCallback() { | |
| this.attachShadow({ mode: 'open' }); | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| .container { | |
| background: #1e293b; | |
| border-radius: 1rem; | |
| padding: 2rem; | |
| border: 1px solid #334155; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| min-height: 400px; | |
| justify-content: center; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .input-area { | |
| width: 100%; | |
| margin-bottom: 1.5rem; | |
| text-align: center; | |
| transition: opacity 0.3s; | |
| } | |
| label { | |
| display: block; | |
| margin-bottom: 0.5rem; | |
| color: #cbd5e1; | |
| font-size: 0.9rem; | |
| font-weight: 500; | |
| } | |
| textarea { | |
| width: 100%; | |
| background: #0f172a; | |
| border: 1px solid #334155; | |
| border-radius: 0.5rem; | |
| padding: 1rem; | |
| color: white; | |
| resize: vertical; | |
| min-height: 100px; | |
| font-family: inherit; | |
| } | |
| textarea:focus { | |
| outline: none; | |
| border-color: #db2777; /* Pink-600 */ | |
| } | |
| .action-btn { | |
| background: linear-gradient(135deg, #db2777, #be185d); | |
| color: white; | |
| border: none; | |
| padding: 0.75rem 2.5rem; | |
| border-radius: 9999px; | |
| font-size: 1.1rem; | |
| font-weight: 700; | |
| cursor: pointer; | |
| box-shadow: 0 4px 20px rgba(219, 39, 119, 0.4); | |
| transition: transform 0.2s, box-shadow 0.2s; | |
| } | |
| .action-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 6px 25px rgba(219, 39, 119, 0.5); | |
| } | |
| .action-btn:active { | |
| transform: scale(0.98); | |
| } | |
| .result-area { | |
| text-align: center; | |
| opacity: 0; | |
| transform: scale(0.9); | |
| transition: all 0.4s ease-out; | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%) scale(0.9); | |
| width: 80%; | |
| } | |
| .result-area.show { | |
| opacity: 1; | |
| transform: translate(-50%, -50%) scale(1); | |
| } | |
| .winner-text { | |
| font-size: 2.5rem; | |
| font-weight: 800; | |
| background: linear-gradient(to right, #f472b6, #db2777); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| margin-bottom: 1rem; | |
| line-height: 1.2; | |
| } | |
| .reset-link { | |
| color: #94a3b8; | |
| text-decoration: underline; | |
| cursor: pointer; | |
| font-size: 0.9rem; | |
| } | |
| .reset-link:hover { | |
| color: #fff; | |
| } | |
| .hint { | |
| font-size: 0.8rem; | |
| color: #64748b; | |
| margin-top: 0.5rem; | |
| } | |
| </style> | |
| <div class="container"> | |
| <div class="input-area" id="inputArea"> | |
| <label for="options">Enter options (separated by commas or new lines)</label> | |
| <textarea id="options" placeholder="e.g. Pizza, Sushi, Salad Go to gym, Sleep, Work"></textarea> | |
| <div class="hint">Analysis paralysis killer</div> | |
| <br> | |
| <button class="action-btn" id="decideBtn">Decide For Me</button> | |
| </div> | |
| <div class="result-area" id="resultArea"> | |
| <div style="font-size: 3rem; margin-bottom: 1rem;">🎲</div> | |
| <div class="winner-text" id="winnerText">Result</div> | |
| <div class="reset-link" id="resetLink">Start Over</div> | |
| </div> | |
| </div> | |
| `; | |
| this.inputArea = this.shadowRoot.getElementById('inputArea'); | |
| this.resultArea = this.shadowRoot.getElementById('resultArea'); | |
| this.textarea = this.shadowRoot.getElementById('options'); | |
| this.decideBtn = this.shadowRoot.getElementById('decideBtn'); | |
| this.resetLink = this.shadowRoot.getElementById('resetLink'); | |
| this.winnerText = this.shadowRoot.getElementById('winnerText'); | |
| this.decideBtn.addEventListener('click', () => this.decide()); | |
| this.resetLink.addEventListener('click', () => this.reset()); | |
| } | |
| decide() { | |
| const raw = this.textarea.value; | |
| // Split by comma or newline, filter empty | |
| const options = raw.split(/[\n,]+/).map(s => s.trim()).filter(s => s.length > 0); | |
| if (options.length < 2) { | |
| // Simple feedback | |
| this.textarea.style.borderColor = '#ef4444'; | |
| setTimeout(() => { | |
| this.textarea.style.borderColor = '#334155'; | |
| }, 1000); | |
| return; | |
| } | |
| // Simulate "thinking" or rolling | |
| this.decideBtn.textContent = 'Rolling...'; | |
| this.decideBtn.disabled = true; | |
| let counter = 0; | |
| const maxRolls = 15; | |
| const interval = setInterval(() => { | |
| this.winnerText.textContent = options[Math.floor(Math.random() * options.length)]; | |
| counter++; | |
| if (counter >= maxRolls) { | |
| clearInterval(interval); | |
| this.showResult(options); | |
| } | |
| }, 80); | |
| } | |
| showResult(options) { | |
| const winner = options[Math.floor(Math.random() * options.length)]; | |
| this.winnerText.textContent = winner; | |
| this.inputArea.style.display = 'none'; | |
| this.resultArea.classList.add('show'); | |
| } | |
| reset() { | |
| this.resultArea.classList.remove('show'); | |
| this.inputArea.style.display = 'block'; | |
| this.decideBtn.textContent = 'Decide For Me'; | |
| this.decideBtn.disabled = false; | |
| this.textarea.value = ''; | |
| this.textarea.focus(); | |
| } | |
| } | |
| customElements.define('tool-decider', ToolDecider); |