Twitch stream event platform with OBS browser source overlay. Features: - Twitch OAuth login (streamer + mod access) - EventSub WebSocket for subs, gift subs, bits, channel points, follows, raids - Chat commands via tmi.js in the overlay - Gap audio — tone plays on new chat message after silence, volume/pitch scale with gap length - Self-hosted media library (upload sounds and videos) - Action configuration — map any event to sound, video, or alert - Per-action cooldowns, test button, enable/disable toggle - Multiple actions per event (all matching actions fire) - Activity log dashboard with EventSub connection status - Layout editor — iframe-based WYSIWYG with drag handles, live style preview - Custom CSS and custom JS injection into overlay - Custom DOM events (bashyoverlay:sub, bashyoverlay:raid, etc.) for custom JS hooks - deploy.sh — one-shot setup and launch script Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
87 lines
4.2 KiB
CSS
87 lines
4.2 KiB
CSS
/* Management UI */
|
|
.login-page { display: flex; align-items: center; justify-content: center; min-height: 80vh; }
|
|
.login-card { text-align: center; max-width: 360px; }
|
|
.twitch-btn { background: #9146ff; border-color: #9146ff; color: #fff; display: inline-block; }
|
|
.twitch-btn:hover { background: #772ce8; border-color: #772ce8; }
|
|
|
|
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
|
|
@media (max-width: 768px) { .form-grid { grid-template-columns: 1fr; } }
|
|
|
|
.status-bar { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 1.5rem; padding: 0.5rem 1rem; border-radius: var(--pico-border-radius); background: var(--pico-card-background-color); }
|
|
.status-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
|
|
.status-dot.connected { background: #2ecc71; }
|
|
.status-dot.disconnected { background: #e74c3c; }
|
|
|
|
.action-row { display: flex; align-items: center; justify-content: space-between; padding: 0.6rem 0; border-bottom: 1px solid var(--pico-table-border-color); gap: 1rem; }
|
|
.action-info { flex: 1; display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
|
|
.action-controls { display: flex; gap: 0.5rem; flex-shrink: 0; }
|
|
|
|
.media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 1rem; }
|
|
.media-item { background: var(--pico-card-background-color); border-radius: var(--pico-border-radius); padding: 0.75rem; display: flex; flex-direction: column; gap: 0.5rem; }
|
|
.media-info { display: flex; align-items: center; gap: 0.5rem; }
|
|
.media-type-badge { font-size: 0.7rem; padding: 0.1rem 0.4rem; border-radius: 999px; font-weight: bold; text-transform: uppercase; }
|
|
.media-type-badge.audio { background: #2980b9; color: #fff; }
|
|
.media-type-badge.video { background: #8e44ad; color: #fff; }
|
|
.media-item audio, .media-item video { width: 100%; }
|
|
|
|
.small-btn { padding: 0.25rem 0.6rem; font-size: 0.8rem; margin-bottom: 0; }
|
|
.tested-badge { color: #2ecc71; font-size: 0.85rem; animation: fadeout 2s ease 1s forwards; }
|
|
@keyframes fadeout { from { opacity: 1; } to { opacity: 0; } }
|
|
.muted { color: var(--pico-muted-color); }
|
|
section { margin-bottom: 2rem; }
|
|
.url-input { font-family: monospace; font-size: 0.85em; }
|
|
.code-textarea { font-family: 'Fira Code', 'Consolas', 'Monaco', monospace; font-size: 0.82rem; resize: vertical; }
|
|
.notice-success { background: #1a3a1a; border: 1px solid #2ecc71; border-radius: var(--pico-border-radius); padding: 0.75rem 1rem; margin-bottom: 1rem; }
|
|
|
|
/* Layout editor */
|
|
.editor-wrap {
|
|
position: relative;
|
|
width: 100%;
|
|
aspect-ratio: 16 / 9;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
border: 1px solid var(--pico-table-border-color);
|
|
background: #000;
|
|
}
|
|
.drag-handle {
|
|
position: absolute;
|
|
border: 2px dashed rgba(145, 70, 255, 0.7);
|
|
border-radius: 4px;
|
|
cursor: move;
|
|
user-select: none;
|
|
z-index: 10;
|
|
box-sizing: border-box;
|
|
transition: border-color 0.1s;
|
|
}
|
|
.drag-handle:hover { border-color: rgba(145, 70, 255, 1); background: rgba(145,70,255,0.08); }
|
|
.handle-label {
|
|
font-size: 0.6rem;
|
|
font-weight: bold;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
color: rgba(145, 70, 255, 0.9);
|
|
padding: 2px 5px;
|
|
background: rgba(0,0,0,0.6);
|
|
border-radius: 2px;
|
|
width: fit-content;
|
|
}
|
|
.resize-corner {
|
|
position: absolute;
|
|
bottom: 0;
|
|
right: 0;
|
|
width: 14px;
|
|
height: 14px;
|
|
background: rgba(145, 70, 255, 0.8);
|
|
border-top-left-radius: 4px;
|
|
cursor: se-resize;
|
|
}
|
|
.canvas-footer { display: flex; justify-content: space-between; align-items: center; margin: 0.4rem 0 1rem; }
|
|
.style-form { margin-top: 0.5rem; }
|
|
.props-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1rem; }
|
|
@media (max-width: 768px) { .props-grid { grid-template-columns: 1fr; } }
|
|
.props-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }
|
|
.props-row label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.85rem; }
|
|
.props-row input[type="number"] { width: 70px; margin-bottom: 0; padding: 0.3rem; }
|
|
.props-row input[type="range"] { width: 100px; margin-bottom: 0; }
|
|
.props-row input[type="color"] { width: 48px; height: 36px; padding: 2px; border-radius: 4px; cursor: pointer; margin-bottom: 0; }
|
|
.props-row span { font-size: 0.75rem; color: var(--pico-muted-color); }
|