π
@@ -196,9 +799,28 @@
display: flex;
gap: 1rem;
justify-content: center;
+ align-items: center;
flex-wrap: wrap;
}
+ .btn-outline {
+ padding: 0.92rem 1.75rem;
+ border-radius: calc(var(--radius) * 1.15);
+ font-weight: 700;
+ border: 1px solid rgba(255, 255, 255, 0.18);
+ background: transparent;
+ color: var(--text-primary);
+ transition: all 0.2s ease;
+ text-decoration: none;
+ display: inline-flex;
+ align-items: center;
+ }
+
+ .btn-outline:hover {
+ background: rgba(255, 255, 255, 0.06);
+ border-color: rgba(99, 102, 241, 0.35);
+ }
+
.btn-secondary {
padding: 0.92rem 1.75rem;
border-radius: calc(var(--radius) * 1.15);
@@ -206,6 +828,11 @@
border: 1px solid rgba(255, 255, 255, 0.18);
background: rgba(255, 255, 255, 0.08);
color: var(--text-primary);
+ cursor: pointer;
+ font: inherit;
+ transition: all 0.2s ease;
+ display: inline-flex;
+ align-items: center;
}
.btn-secondary:hover {
@@ -213,6 +840,663 @@
border-color: rgba(99, 102, 241, 0.45);
}
+ /* --- Create Card Form Styles --- */
+ .create-card-section {
+ padding: clamp(2rem, 5vw, 3.5rem) clamp(1.5rem, 4vw, 3rem);
+ border-radius: var(--radius-xl, 24px);
+ margin: 3rem auto 5rem;
+ background: rgba(15, 23, 42, 0.7);
+ backdrop-filter: blur(16px);
+ -webkit-backdrop-filter: blur(16px);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+ box-shadow: var(--shadow-xl);
+ max-width: 800px;
+ position: relative;
+ overflow: hidden;
+ }
+
+ .section-header {
+ text-align: center;
+ margin-bottom: 2.5rem;
+ }
+
+ .logo-accent {
+ font-size: 2.5rem;
+ margin-bottom: 0.5rem;
+ display: inline-block;
+ animation: pulse 2s infinite;
+ }
+
+ .create-card-section h2 {
+ font-size: clamp(1.8rem, 3.2vw, 2.5rem);
+ font-weight: 800;
+ margin-bottom: 0.75rem;
+ background: linear-gradient(135deg, #fff 0%, var(--text-secondary) 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ }
+
+ .section-subtitle {
+ color: var(--text-secondary);
+ font-size: 1.05rem;
+ max-width: 550px;
+ margin: 0 auto;
+ line-height: 1.5;
+ }
+
+ .section-subtitle-sm {
+ color: var(--text-muted);
+ font-size: 0.9rem;
+ margin-bottom: 1.25rem;
+ line-height: 1.4;
+ }
+
+ .card-form {
+ display: flex;
+ flex-direction: column;
+ gap: 2rem;
+ }
+
+ .form-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 1.5rem;
+ }
+
+ @media (max-width: 640px) {
+ .form-grid {
+ grid-template-columns: 1fr;
+ }
+ }
+
+ .form-group {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+
+ .form-group.full-width {
+ grid-column: span 2;
+ }
+
+ @media (max-width: 640px) {
+ .form-group.full-width {
+ grid-column: span 1;
+ }
+ }
+
+ label, .studio-title-label {
+ font-size: 0.9rem;
+ font-weight: 600;
+ color: var(--text-primary);
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ }
+
+ .required {
+ color: #ef4444;
+ }
+
+ .optional {
+ color: var(--text-muted);
+ font-size: 0.8rem;
+ font-weight: normal;
+ }
+
+ input, select, textarea {
+ background: rgba(255, 255, 255, 0.04);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+ border-radius: var(--radius);
+ padding: 0.75rem 1rem;
+ color: var(--text-primary);
+ font-size: 1rem;
+ font-family: inherit;
+ transition: all 0.2s ease;
+ }
+
+ input:focus, select:focus, textarea:focus {
+ outline: none;
+ border-color: rgba(99, 102, 241, 0.5);
+ background: rgba(255, 255, 255, 0.08);
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15);
+ }
+
+ .input-with-prefix {
+ display: flex;
+ align-items: stretch;
+ border-radius: var(--radius);
+ background: rgba(255, 255, 255, 0.04);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+ overflow: hidden;
+ transition: all 0.2s ease;
+ }
+
+ .input-with-prefix:focus-within {
+ border-color: rgba(99, 102, 241, 0.5);
+ background: rgba(255, 255, 255, 0.08);
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15);
+ }
+
+ .input-with-prefix input {
+ border: none;
+ background: transparent;
+ padding-left: 0.35rem;
+ flex: 1;
+ box-shadow: none;
+ }
+
+ .input-with-prefix input:focus {
+ border: none;
+ box-shadow: none;
+ background: transparent;
+ }
+
+ .url-prefix {
+ display: flex;
+ align-items: center;
+ padding: 0 0.75rem;
+ background: rgba(255, 255, 255, 0.04);
+ color: var(--text-muted);
+ font-size: 0.95rem;
+ border-right: 1px solid rgba(255, 255, 255, 0.08);
+ font-weight: 500;
+ }
+
+ .input-helper {
+ font-size: 0.8rem;
+ color: var(--text-muted);
+ }
+
+ /* --- Avatar Studio Styles --- */
+ .avatar-studio-group {
+ margin-bottom: 0.5rem;
+ }
+
+ .avatar-studio-container {
+ display: flex;
+ gap: 2rem;
+ padding: 1.5rem;
+ border-radius: var(--radius-xl);
+ background: rgba(255, 255, 255, 0.02);
+ border: 1px solid rgba(255, 255, 255, 0.06);
+ align-items: center;
+ }
+
+ @media (max-width: 640px) {
+ .avatar-studio-container {
+ flex-direction: column;
+ align-items: center;
+ gap: 1.5rem;
+ }
+ }
+
+ .avatar-preview-box {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.5rem;
+ min-width: 120px;
+ }
+
+ .preview-avatar-wrapper {
+ position: relative;
+ width: 110px;
+ height: 110px;
+ border-radius: 32% 68% 63% 37% / 34% 36% 64% 66%;
+ background: linear-gradient(135deg, #6366f1 0%, #a855f7 100%);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: 3px solid rgba(255, 255, 255, 0.15);
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
+ overflow: hidden;
+ }
+
+ .studio-preview-image {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+
+ .studio-preview-placeholder {
+ font-size: 2.75rem;
+ font-weight: 800;
+ color: white;
+ }
+
+ .preview-label {
+ font-size: 0.8rem;
+ color: var(--text-muted);
+ font-weight: 600;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+ }
+
+ .avatar-studio-controls {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 1.25rem;
+ width: 100%;
+ }
+
+ .control-section {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+
+ .row-controls {
+ display: flex;
+ flex-direction: row;
+ gap: 1.5rem;
+ }
+
+ @media (max-width: 520px) {
+ .row-controls {
+ flex-direction: column;
+ gap: 1rem;
+ }
+ }
+
+ .sub-control {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+
+ .control-label {
+ font-size: 0.82rem;
+ font-weight: 700;
+ color: var(--text-secondary);
+ letter-spacing: 0.3px;
+ }
+
+ .preset-avatars-grid {
+ display: flex;
+ gap: 0.75rem;
+ flex-wrap: wrap;
+ }
+
+ .preset-btn {
+ width: 38px;
+ height: 38px;
+ border-radius: 50%;
+ background-size: cover;
+ background-position: center;
+ border: 2px solid rgba(255, 255, 255, 0.12);
+ cursor: pointer;
+ transition: all 0.2s ease;
+ padding: 0;
+ }
+
+ .preset-btn:hover {
+ transform: scale(1.1);
+ border-color: var(--primary, #6366f1);
+ }
+
+ .preset-btn.active {
+ border-color: var(--primary, #6366f1);
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.3);
+ transform: scale(1.05);
+ }
+
+ .suggestions-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(85px, 1fr));
+ gap: 0.75rem;
+ width: 100%;
+ }
+
+ .suggestion-card {
+ background: rgba(255, 255, 255, 0.03);
+ border: 1px solid rgba(255, 255, 255, 0.06);
+ border-radius: 12px;
+ padding: 0.5rem;
+ cursor: pointer;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.35rem;
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ outline: none;
+ }
+
+ .suggestion-card:hover:not(:disabled) {
+ background: rgba(255, 255, 255, 0.08);
+ border-color: rgba(99, 102, 241, 0.3);
+ transform: translateY(-2px);
+ }
+
+ .suggestion-card.active {
+ background: rgba(99, 102, 241, 0.08);
+ border-color: var(--primary, #6366f1);
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.25);
+ }
+
+ .suggestion-card:disabled {
+ opacity: 0.4;
+ cursor: not-allowed;
+ }
+
+ .suggestion-preview {
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(255, 255, 255, 0.05);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ }
+
+ .suggestion-preview img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+
+ .suggestion-placeholder {
+ font-size: 0.95rem;
+ font-weight: 700;
+ color: var(--text-muted);
+ }
+
+ .suggestion-name {
+ font-size: 0.72rem;
+ font-weight: 600;
+ color: var(--text-secondary);
+ text-align: center;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ width: 100%;
+ }
+
+ .github-sync-control {
+ min-width: 140px;
+ }
+
+ .btn-github-sync {
+ padding: 0.5rem 1rem;
+ font-size: 0.85rem;
+ font-weight: 700;
+ color: white;
+ background: #24292e;
+ border: 1px solid rgba(255, 255, 255, 0.15);
+ border-radius: 6px;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .btn-github-sync:hover {
+ background: #2f363d;
+ border-color: rgba(99, 102, 241, 0.4);
+ transform: translateY(-1px);
+ }
+
+ textarea {
+ resize: vertical;
+ }
+
+ .textarea-footer {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: -0.25rem;
+ }
+
+ .char-count {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ }
+
+ /* --- Links Section in Form --- */
+ .links-section-form {
+ border-top: 1px solid rgba(255, 255, 255, 0.08);
+ padding-top: 1.75rem;
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ }
+
+ .links-section-form h3 {
+ font-size: 1.25rem;
+ font-weight: 700;
+ }
+
+ .link-builder-row {
+ display: flex;
+ gap: 0.75rem;
+ align-items: center;
+ flex-wrap: wrap;
+ }
+
+ .link-builder-row input {
+ flex: 1;
+ min-width: 200px;
+ }
+
+ .select-wrapper {
+ position: relative;
+ display: flex;
+ }
+
+ .select-wrapper select {
+ appearance: none;
+ padding-right: 2.5rem;
+ cursor: pointer;
+ background: rgba(255, 255, 255, 0.04);
+ }
+
+ .select-wrapper::after {
+ content: "βΌ";
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ position: absolute;
+ right: 1rem;
+ top: 50%;
+ transform: translateY(-50%);
+ pointer-events: none;
+ }
+
+ .btn-add-link {
+ padding: 0.75rem 1.25rem;
+ background: rgba(255, 255, 255, 0.06);
+ border: 1px solid rgba(255, 255, 255, 0.12);
+ border-radius: var(--radius);
+ font-weight: 600;
+ color: var(--text-primary);
+ cursor: pointer;
+ transition: all 0.2s ease;
+ white-space: nowrap;
+ }
+
+ .btn-add-link:hover {
+ background: rgba(255, 255, 255, 0.12);
+ border-color: rgba(99, 102, 241, 0.4);
+ transform: translateY(-1px);
+ }
+
+ /* --- Links List Container --- */
+ .links-list-container {
+ background: rgba(0, 0, 0, 0.12);
+ border: 1px dashed rgba(255, 255, 255, 0.06);
+ border-radius: var(--radius-xl);
+ padding: 1rem;
+ min-height: 80px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ }
+
+ .empty-links-state {
+ text-align: center;
+ color: var(--text-muted);
+ padding: 1rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.35rem;
+ }
+
+ .empty-icon {
+ font-size: 1.5rem;
+ opacity: 0.5;
+ }
+
+ .links-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+ }
+
+ .link-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0.75rem 1rem;
+ border-radius: var(--radius);
+ background: rgba(255, 255, 255, 0.03);
+ border: 1px solid rgba(255, 255, 255, 0.05);
+ gap: 1rem;
+ }
+
+ .link-item-info {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ flex-wrap: wrap;
+ flex: 1;
+ }
+
+ .link-platform-tag {
+ font-size: 0.8rem;
+ font-weight: 700;
+ padding: 0.25rem 0.65rem;
+ border-radius: 999px;
+ color: white;
+ box-shadow: 0 2px 5px rgba(0,0,0,0.15);
+ }
+
+ .link-username-tag {
+ font-size: 0.9rem;
+ font-weight: 600;
+ color: var(--text-primary);
+ }
+
+ .link-url-tag {
+ font-size: 0.82rem;
+ color: var(--text-muted);
+ max-width: 320px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .btn-delete-link {
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ font-size: 1.1rem;
+ padding: 0.25rem;
+ opacity: 0.6;
+ transition: opacity 0.2s ease, transform 0.2s ease;
+ }
+
+ .btn-delete-link:hover {
+ opacity: 1;
+ transform: scale(1.15);
+ }
+
+ /* --- Form Alerts --- */
+ .alert {
+ padding: 1rem;
+ border-radius: var(--radius);
+ font-size: 0.95rem;
+ font-weight: 500;
+ border-left: 4px solid;
+ margin-bottom: 1.5rem;
+ }
+
+ .alert-error {
+ background: rgba(239, 68, 68, 0.06);
+ border: 1px solid rgba(239, 68, 68, 0.12);
+ border-left-color: #ef4444;
+ color: #fca5a5;
+ }
+
+ .alert-success {
+ background: rgba(34, 197, 94, 0.06);
+ border: 1px solid rgba(34, 197, 94, 0.12);
+ border-left-color: #22c55e;
+ color: #86efac;
+ }
+
+ /* --- Form Action Buttons --- */
+ .form-submit-wrapper {
+ display: flex;
+ gap: 1rem;
+ align-items: center;
+ border-top: 1px solid rgba(255, 255, 255, 0.08);
+ padding-top: 1.75rem;
+ margin-top: 0.5rem;
+ }
+
+ .btn-generate-card {
+ padding: 0.9rem 2rem;
+ font-weight: 700;
+ border: none;
+ cursor: pointer;
+ background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);
+ color: white;
+ border-radius: calc(var(--radius) * 1.15);
+ box-shadow: 0 10px 25px -10px rgba(99, 102, 241, 0.4);
+ transition: all 0.25s ease;
+ display: inline-flex;
+ align-items: center;
+ }
+
+ .btn-generate-card:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 15px 30px -10px rgba(99, 102, 241, 0.5);
+ }
+
+ .btn-generate-card:active {
+ transform: translateY(0);
+ }
+
+ .btn-primary {
+ background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);
+ color: white;
+ border: none;
+ box-shadow: 0 10px 25px -10px rgba(99, 102, 241, 0.4);
+ text-decoration: none;
+ padding: 0.92rem 1.75rem;
+ border-radius: calc(var(--radius) * 1.15);
+ font-weight: 700;
+ transition: all 0.25s ease;
+ display: inline-flex;
+ align-items: center;
+ }
+
+ .btn-primary:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 15px 30px -10px rgba(99, 102, 241, 0.5);
+ }
+
+ /* Smooth animations */
+ @keyframes pulse {
+ 0%, 100% { transform: scale(1); opacity: 1; }
+ 50% { transform: scale(1.08); opacity: 0.85; }
+ }
+
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
@@ -221,13 +1505,13 @@
}
@media (max-width: 640px) {
- .features {
- display: grid;
- grid-template-columns: 1fr; /* single column */
- gap: 16px;
- padding: 0 12px;
+ .features {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 16px;
+ padding: 0 12px;
+ }
}
-}
.feature-card {
padding: 2.4rem;
@@ -236,17 +1520,15 @@
background: linear-gradient(180deg, rgba(15, 23, 42, 0.75), rgba(15, 23, 42, 0.5));
border: 1px solid rgba(255, 255, 255, 0.08);
transition: transform 0.35s ease, border-color 0.35s ease, box-shadow 0.35s ease;
+ min-height: 140px;
}
- .feature-card {
- min-height: 140px;
- padding: 16px;
-}
-@media (max-width: 640px) {
- .feature-card {
- margin-bottom: 12px;
+ @media (max-width: 640px) {
+ .feature-card {
+ margin-bottom: 12px;
+ padding: 1.8rem;
+ }
}
-}
.feature-card:hover {
transform: translateY(-8px);
@@ -297,10 +1579,6 @@
align-items: stretch;
}
- .feature-card {
- padding: 1.8rem;
- }
-
.features {
gap: 1.2rem;
}
diff --git a/apps/web/src/routes/u/[username]/+page.server.ts b/apps/web/src/routes/u/[username]/+page.server.ts
index 042acad..8882b45 100644
--- a/apps/web/src/routes/u/[username]/+page.server.ts
+++ b/apps/web/src/routes/u/[username]/+page.server.ts
@@ -1,16 +1,2 @@
-import type { PageServerLoad } from './$types';
-
-const API_BASE = process.env.BACKEND_URL || 'http://localhost:3000';
-
-export const load: PageServerLoad = async ({ params, fetch }) => {
- try {
- const res = await fetch(`${API_BASE}/api/u/${params.username}?source=web`);
- if (!res.ok) {
- return { profile: null, error: 'User not found' };
- }
- const profile = await res.json();
- return { profile, error: null };
- } catch {
- return { profile: null, error: 'Failed to load profile' };
- }
-};
+// This server load is intentionally disabled. Profile data is loaded client-side from localStorage.
+export const load = async () => ({ profile: null, error: null });
diff --git a/apps/web/src/routes/u/[username]/+page.svelte b/apps/web/src/routes/u/[username]/+page.svelte
index bb23cca..c4318ef 100644
--- a/apps/web/src/routes/u/[username]/+page.svelte
+++ b/apps/web/src/routes/u/[username]/+page.svelte
@@ -1,26 +1,69 @@
@@ -62,19 +137,25 @@
{profile.displayName} | DevCard
{:else}
-
User Not Found | DevCard
+
Card Not Found | DevCard
{/if}
- {#if error || !profile}
+ {#if errorStatus}
π
-
Profile not found
+
Card not found
This DevCard has vanished into the digital void.
-
Return Home
+
Create yours
+
+ {:else if !profile}
+
+
+
β‘
+
Retrieving your DevCard...
{:else}
@@ -91,11 +172,9 @@
{profile.displayName}
- {#if profile.role}
-
- {profile.role}{profile.company ? ` @ ${profile.company}` : ''}
-
- {/if}
+
+ @{profile.username}
+
{#if profile.bio}
{profile.bio}
@@ -104,26 +183,39 @@
+
+
+
+
+
+
Share Your Profile
+
Scan to view or tap below to download QR as a high-quality PNG.
+
+
+
-
Want a card like this?
@@ -268,6 +360,8 @@
animation: slideIn 0.5s ease-out forwards;
animation-delay: var(--delay);
opacity: 0;
+ text-decoration: none;
+ color: inherit;
}
.link-tile:hover,
@@ -329,8 +423,75 @@
transform: translateX(5px);
}
+ /* --- QR Section Styles --- */
+ .qr-section {
+ margin-top: 2.25rem;
+ padding: 1.5rem;
+ border-radius: var(--radius-lg, 16px);
+ background: rgba(255, 255, 255, 0.03);
+ border: 1px solid rgba(255, 255, 255, 0.06);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 1.5rem;
+ flex-wrap: wrap;
+ }
+
+ .qr-canvas {
+ border-radius: 12px;
+ background: white;
+ padding: 6px;
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35);
+ width: 140px;
+ height: 140px;
+ }
+
+ .qr-actions {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0.45rem;
+ flex: 1;
+ min-width: 180px;
+ }
+
+ .qr-title {
+ font-size: 1.1rem;
+ font-weight: 700;
+ color: var(--text-primary);
+ }
+
+ .qr-hint {
+ font-size: 0.85rem;
+ color: var(--text-muted);
+ line-height: 1.45;
+ margin-bottom: 0.25rem;
+ }
+
+ .btn-qr-download {
+ border: 1px solid rgba(255, 255, 255, 0.15);
+ border-radius: var(--radius);
+ background: rgba(255, 255, 255, 0.08);
+ color: var(--text-primary);
+ cursor: pointer;
+ font: inherit;
+ font-weight: 700;
+ padding: 0.55rem 1.1rem;
+ font-size: 0.9rem;
+ transition: all 0.2s ease;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.4rem;
+ }
+
+ .btn-qr-download:hover {
+ background: rgba(255, 255, 255, 0.15);
+ transform: translateY(-1px);
+ border-color: var(--accent);
+ }
+
.card-footer {
- margin-top: 2.5rem;
+ margin-top: 2.25rem;
padding-top: 1.75rem;
border-top: 1px solid rgba(255,255,255,0.08);
display: flex;
@@ -349,16 +510,10 @@
}
.get-your-own {
- margin-top: 2rem;
+ margin-top: 2.25rem;
text-align: center;
}
- .get-your-own p {
- margin-bottom: 0.5rem;
- font-size: 0.95rem;
- color: var(--text-muted);
- }
-
.profile-actions {
display: flex;
flex-wrap: wrap;
@@ -367,26 +522,25 @@
gap: 0.75rem;
}
- .get-devcard-link {
- font-weight: 700;
- font-size: 1.05rem;
- }
-
.copy-link-button {
- border: 1px solid var(--border-glass);
+ border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: var(--radius);
- background: rgba(255, 255, 255, 0.08);
+ background: rgba(255, 255, 255, 0.06);
color: var(--text-primary);
cursor: pointer;
font: inherit;
font-weight: 700;
- padding: 0.65rem 1rem;
+ padding: 0.65rem 1.2rem;
transition: all 0.2s ease;
+ text-decoration: none;
+ display: inline-flex;
+ align-items: center;
}
.copy-link-button:hover {
- background: rgba(255, 255, 255, 0.15);
+ background: rgba(255, 255, 255, 0.14);
transform: translateY(-1px);
+ border-color: var(--accent);
}
.copy-link-button:focus-visible {
@@ -411,9 +565,63 @@
.error-glass {
text-align: center;
- padding: 3rem;
+ padding: 3.5rem clamp(1.5rem, 4vw, 3rem);
border-radius: var(--radius-xl);
width: min(100%, 520px);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 26px 60px -20px rgba(0, 0, 0, 0.55);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+ background: rgba(15, 23, 42, 0.96);
+ }
+
+ .error-glass h1 {
+ font-size: 2rem;
+ margin-bottom: 0.75rem;
+ }
+
+ .error-glass p {
+ color: var(--text-secondary);
+ margin-bottom: 1.75rem;
+ line-height: 1.5;
+ }
+
+ .error-emoji {
+ font-size: 3.5rem;
+ margin-bottom: 1.25rem;
+ }
+
+ .spinner {
+ font-size: 3rem;
+ margin-bottom: 1.25rem;
+ animation: rotate 1.5s linear infinite;
+ }
+
+ @keyframes rotate {
+ 0% { transform: rotate(0deg) scale(1); }
+ 50% { transform: rotate(180deg) scale(1.1); }
+ 100% { transform: rotate(360deg) scale(1); }
+ }
+
+ .btn-primary {
+ background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);
+ color: white;
+ border: none;
+ box-shadow: 0 10px 25px -10px rgba(99, 102, 241, 0.4);
+ text-decoration: none;
+ padding: 0.8rem 1.75rem;
+ border-radius: calc(var(--radius) * 1.15);
+ font-weight: 700;
+ transition: all 0.25s ease;
+ display: inline-flex;
+ align-items: center;
+ }
+
+ .btn-primary:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 15px 30px -10px rgba(99, 102, 241, 0.5);
}
@media (max-width: 720px) {
@@ -421,6 +629,7 @@
.profile-header { margin-bottom: 2rem; }
.avatar-wrapper { width: 108px; height: 108px; margin-bottom: 1.5rem; }
.card-footer { flex-direction: column; align-items: flex-start; }
+ .qr-section { gap: 1rem; padding: 1.2rem; }
}
@media (max-width: 520px) {
@@ -429,5 +638,7 @@
.link-tile { padding: 0.95rem; }
.tile-content { margin-left: 0.9rem; }
.card-footer { text-align: left; }
+ .qr-section { flex-direction: column; align-items: center; text-align: center; }
+ .qr-actions { align-items: center; }
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5badd09..05218f8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -247,6 +247,9 @@ importers:
'@devcard/shared':
specifier: workspace:*
version: link:../../packages/shared
+ qrcode:
+ specifier: ^1.5.4
+ version: 1.5.4
devDependencies:
'@sveltejs/adapter-auto':
specifier: ^7.0.0
@@ -257,6 +260,9 @@ importers:
'@sveltejs/vite-plugin-svelte':
specifier: ^6.2.4
version: 6.2.4(svelte@5.53.10)(vite@7.3.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))
+ '@types/qrcode':
+ specifier: ^1.5.6
+ version: 1.5.6
svelte:
specifier: ^5.51.0
version: 5.53.10