Portfolio/styles.css
Max 186baa1239 Transform portfolio into live playground with real-time results
- Separated JavaScript into script.js for better organization
- Added Server-Sent Events (SSE) webhook receiver for real-time results
- Created Go service to receive AlpenQueue webhooks and broadcast via SSE
- Removed manual webhook input - results stream automatically
- Added live connection status indicator
- Implemented real-time result cards with animations
- Fixed AlpenQueue API field names (webhook_url, selector)
- Added dark theme styling for result display
- Results appear instantly without polling

The portfolio now shows AlpenQueue results in real-time as they arrive!
2025-11-16 17:43:17 +00:00

389 lines
6.0 KiB
CSS

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Courier New', monospace;
line-height: 1.6;
padding: 2rem;
max-width: 800px;
margin: 0 auto;
background: #0a0a0a;
color: #e0e0e0;
}
h1 {
font-size: 1.1rem;
font-weight: normal;
margin-bottom: 1.5rem;
color: #4a9e5f;
}
h2 {
font-size: 1.05rem;
font-weight: normal;
color: #4a9e5f;
margin-bottom: 1rem;
}
.intro {
margin-bottom: 2rem;
font-size: 0.95rem;
line-height: 1.7;
}
.project {
margin: 2rem 0;
padding: 1.5rem;
border-left: 2px solid #333;
background: #111;
}
.project-name {
color: #4a9e5f;
font-weight: bold;
margin-bottom: 0.5rem;
}
.project p {
margin-top: 0.5rem;
}
.playground {
margin: 2.5rem 0;
padding: 2rem;
background: #111;
border: 1px solid #222;
}
.playground-intro {
margin-bottom: 1.5rem;
font-size: 0.95rem;
color: #b0b0b0;
}
#queue-form {
margin: 1.5rem 0;
}
.form-group {
margin-bottom: 1.25rem;
}
.form-group label {
display: block;
margin-bottom: 0.4rem;
font-size: 0.95rem;
color: #e0e0e0;
}
.form-group input {
width: 100%;
padding: 0.6rem 0.8rem;
background: #0a0a0a;
border: 1px solid #333;
color: #e0e0e0;
font-family: 'Courier New', monospace;
font-size: 0.95rem;
transition: border-color 0.2s;
}
.form-group input:focus {
outline: none;
border-color: #4a9e5f;
}
.form-group small {
display: block;
margin-top: 0.3rem;
font-size: 0.85rem;
color: #666;
}
.form-group small a {
color: #4a9e5f;
text-decoration: none;
}
.form-group small a:hover {
text-decoration: underline;
}
button[type="submit"] {
background: #4a9e5f;
color: #fff;
border: none;
padding: 0.7rem 1.5rem;
font-family: 'Courier New', monospace;
font-size: 0.95rem;
cursor: pointer;
transition: all 0.2s;
}
button[type="submit"]:hover:not(:disabled) {
background: #5fb070;
}
button[type="submit"]:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.response-box {
margin: 1.5rem 0;
padding: 1rem;
border: 1px solid #333;
background: #0f0f0f;
min-height: 60px;
display: none;
}
.response-box.loading,
.response-box.success,
.response-box.error {
display: flex;
align-items: center;
}
.response-box.loading {
border-color: #4a9e5f;
color: #4a9e5f;
}
.response-box.success {
border-color: #4a9e5f;
background: #0a1a0f;
}
.response-box.error {
border-color: #9e4a4a;
background: #1a0a0a;
}
.success-icon,
.error-icon {
font-size: 1.5rem;
margin-right: 1rem;
}
.success-icon {
color: #4a9e5f;
}
.error-icon {
color: #9e4a4a;
}
.response-content {
flex: 1;
}
.response-content code {
background: #222;
padding: 0.2rem 0.4rem;
margin: 0 0.2rem;
font-size: 0.9rem;
}
.spinner {
display: inline-block;
width: 16px;
height: 16px;
border: 2px solid #4a9e5f;
border-top-color: transparent;
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin-right: 0.5rem;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.stats-live {
margin-top: 1.5rem;
display: flex;
justify-content: space-around;
border-top: 1px solid #222;
padding-top: 1rem;
}
.stat-item {
text-align: center;
}
.stat-label {
font-size: 0.85rem;
color: #666;
display: block;
}
.stat-value {
font-size: 1.1rem;
color: #4a9e5f;
font-weight: bold;
display: block;
margin-top: 0.3rem;
}
.stack {
margin: 2rem 0;
font-size: 0.95rem;
}
.link {
margin-top: 1.5rem;
font-size: 0.95rem;
}
.link a {
color: #4a9e5f;
text-decoration: none;
border-bottom: 1px solid #4a9e5f;
}
.link a:hover {
color: #5fb070;
border-bottom-color: #5fb070;
}
/* Live results container */
.live-results-container {
margin: 2rem 0;
padding: 1.5rem;
background: #111;
border: 1px solid #222;
}
.results-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid #222;
}
.results-header h3 {
margin: 0;
font-size: 1rem;
color: #4a9e5f;
font-weight: normal;
}
.connection-status {
font-size: 0.85rem;
color: #666;
}
.connection-status.connected {
color: #4a9e5f;
}
.live-results {
min-height: 200px;
max-height: 600px;
overflow-y: auto;
}
.no-results {
text-align: center;
color: #666;
padding: 2rem;
font-size: 0.9rem;
}
.result-item {
margin-bottom: 1rem;
padding: 1rem;
background: #0a0a0a;
border: 1px solid #222;
border-left: 3px solid #4a9e5f;
}
.result-item.error {
border-left-color: #9e4a4a;
}
.result-item.blocked {
border-left-color: #9e9e4a;
}
.result-header {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
font-size: 0.85rem;
}
.result-status {
font-weight: bold;
padding: 0.2rem 0.5rem;
border-radius: 3px;
}
.result-status.ok {
background: #1a3a1f;
color: #4a9e5f;
}
.result-status.error {
background: #3a1a1a;
color: #9e4a4a;
}
.result-status.blocked {
background: #3a3a1a;
color: #9e9e4a;
}
.result-time {
color: #666;
}
.result-url {
font-size: 0.9rem;
color: #4a9e5f;
margin-bottom: 0.5rem;
word-break: break-all;
}
.result-content {
margin-top: 0.5rem;
}
.result-content pre {
margin: 0;
padding: 0.5rem;
background: #000;
border: 1px solid #1a1a1a;
font-family: 'Courier New', monospace;
font-size: 0.85rem;
color: #b0b0b0;
white-space: pre-wrap;
word-wrap: break-word;
overflow-x: auto;
}
.result-content em {
color: #666;
font-size: 0.85rem;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Hide the old results explanation */
.results-explanation {
display: none;
}