|
{% extends "base.html" %}
|
|
{% block extra_head %}
|
|
<link rel="stylesheet" href="/static/css/feed.css">
|
|
<link rel="stylesheet" href="/static/css/profile.css">
|
|
<link rel="stylesheet" href="/static/css/projects.css">
|
|
<link rel="stylesheet" href="/static/css/gists.css">
|
|
{% endblock %}
|
|
{% block content %}
|
|
<div class="profile-layout">
|
|
<aside class="profile-sidebar">
|
|
<div class="profile-card">
|
|
<div class="profile-avatar-wrap">
|
|
<img src="{{ avatar_url('multiavatar', profile_user['username'], 80) }}" class="avatar-img avatar-lg" alt="{{ profile_user['username'] }}" id="profile-avatar-preview" loading="lazy">
|
|
</div>
|
|
<h1 class="profile-name">{{ profile_user['username'] }}</h1>
|
|
{% if profile_user.get('role') %}
|
|
<div class="profile-role">{{ profile_user['role'] }}</div>
|
|
{% endif %}
|
|
|
|
<div class="profile-stats">
|
|
<div class="profile-stat">
|
|
<span class="profile-stat-value">{{ posts_count }}</span>
|
|
<span class="profile-stat-label">Posts</span>
|
|
</div>
|
|
<div class="profile-stat">
|
|
<span class="profile-stat-value">{{ profile_user.get('level', 1) }}</span>
|
|
<span class="profile-stat-label">Level</span>
|
|
</div>
|
|
<div class="profile-stat">
|
|
<span class="profile-stat-value">{{ profile_user.get('stars', 0) }}</span>
|
|
<span class="profile-stat-label">Stars</span>
|
|
</div>
|
|
<div class="profile-stat">
|
|
<a href="/leaderboard" class="profile-stat-value">{% if rank %}#{{ rank }}{% else %}—{% endif %}</a>
|
|
<span class="profile-stat-label">Rank</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="profile-level-bar">
|
|
<div class="level-label">
|
|
<span>Progress to next level</span>
|
|
<span>{{ profile_user.get('xp', 0) % 100 }}%</span>
|
|
</div>
|
|
<div class="bar">
|
|
<div class="bar-fill" style="width: {{ profile_user.get('xp', 0) % 100 }}%;"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="profile-badges">
|
|
{% for badge in badges %}
|
|
{% set meta = badge_info(badge['badge_name']) %}
|
|
<span class="profile-badge" title="{{ meta['description'] }}"><span class="profile-badge-icon">{{ meta['icon'] }}</span>{{ badge['badge_name'] }}</span>
|
|
{% else %}
|
|
{% set meta = badge_info('Member') %}
|
|
<span class="profile-badge" title="{{ meta['description'] }}"><span class="profile-badge-icon">{{ meta['icon'] }}</span>Member</span>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
{% if user and user['uid'] != profile_user['uid'] %}
|
|
<div class="profile-actions">
|
|
<a href="/messages?with_uid={{ profile_user['uid'] }}" class="btn btn-secondary btn-sm full-width justify-center"><span class="icon">✉️</span>Send Message</a>
|
|
{% if is_following %}
|
|
<form method="POST" action="/follow/unfollow/{{ profile_user['username'] }}">
|
|
<button type="submit" class="btn btn-secondary btn-sm full-width"><span class="icon">➖</span>Unfollow</button>
|
|
</form>
|
|
{% else %}
|
|
<form method="POST" action="/follow/{{ profile_user['username'] }}">
|
|
<button type="submit" class="btn btn-primary btn-sm full-width"><span class="icon">➕</span>Follow</button>
|
|
</form>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if user and user['uid'] == profile_user['uid'] %}
|
|
<div class="profile-info">
|
|
<form method="POST" action="/profile/update">
|
|
<div class="profile-info-row">
|
|
<span class="profile-info-label">Bio</span>
|
|
<div class="flex-center-gap">
|
|
<span class="profile-info-value bio-display" id="display-bio">{{ profile_user.get('bio', '') or 'Not set' }}</span>
|
|
<button type="button" class="profile-info-edit" data-edit-field="bio">✎</button>
|
|
</div>
|
|
</div>
|
|
<div class="auth-field hidden input-edit-field" id="input-bio">
|
|
<textarea name="bio" maxlength="500" rows="2" class="input-sm">{{ profile_user.get('bio', '') }}</textarea>
|
|
</div>
|
|
|
|
<div class="profile-info-row">
|
|
<span class="profile-info-label">Location</span>
|
|
<div class="flex-center-gap">
|
|
<span class="profile-info-value" id="display-location">{{ profile_user.get('location', '') or 'Not set' }}</span>
|
|
<button type="button" class="profile-info-edit" data-edit-field="location">✎</button>
|
|
</div>
|
|
</div>
|
|
<div class="auth-field hidden input-edit-field" id="input-location">
|
|
<input type="text" name="location" maxlength="200" value="{{ profile_user.get('location', '') }}" class="input-sm">
|
|
</div>
|
|
|
|
<div class="profile-info-row">
|
|
<span class="profile-info-label">Git Link</span>
|
|
<div class="flex-center-gap">
|
|
<span class="profile-info-value" id="display-git_link">{{ profile_user.get('git_link', '') or 'Not set' }}</span>
|
|
<button type="button" class="profile-info-edit" data-edit-field="git_link">✎</button>
|
|
</div>
|
|
</div>
|
|
<div class="auth-field hidden input-edit-field" id="input-git_link">
|
|
<input type="url" name="git_link" maxlength="500" value="{{ profile_user.get('git_link', '') }}" class="input-sm">
|
|
</div>
|
|
|
|
<div class="profile-info-row">
|
|
<span class="profile-info-label">Website</span>
|
|
<div class="flex-center-gap">
|
|
<span class="profile-info-value" id="display-website">{{ profile_user.get('website', '') or 'Not set' }}</span>
|
|
<button type="button" class="profile-info-edit" data-edit-field="website">✎</button>
|
|
</div>
|
|
</div>
|
|
<div class="auth-field hidden input-edit-field" id="input-website">
|
|
<input type="url" name="website" maxlength="500" value="{{ profile_user.get('website', '') }}" class="input-sm">
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-primary btn-sm full-width save-btn-top">Save Changes</button>
|
|
</form>
|
|
</div>
|
|
{% else %}
|
|
<div class="profile-info">
|
|
<div class="profile-info-row">
|
|
<span class="profile-info-label">Bio</span>
|
|
<span class="profile-info-value">{{ profile_user.get('bio', '') or 'Not set' }}</span>
|
|
</div>
|
|
<div class="profile-info-row">
|
|
<span class="profile-info-label">Location</span>
|
|
<span class="profile-info-value">{{ profile_user.get('location', '') or 'Not set' }}</span>
|
|
</div>
|
|
<div class="profile-info-row">
|
|
<span class="profile-info-label">Git Link</span>
|
|
<span class="profile-info-value">{{ profile_user.get('git_link', '') or 'Not set' }}</span>
|
|
</div>
|
|
<div class="profile-info-row">
|
|
<span class="profile-info-label">Website</span>
|
|
<span class="profile-info-value">{{ profile_user.get('website', '') or 'Not set' }}</span>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</aside>
|
|
|
|
<div class="profile-content">
|
|
<a href="/feed" class="back-link">← Back</a>
|
|
|
|
<div class="profile-heatmap-card">
|
|
<div class="heatmap-header">
|
|
<h3 class="heatmap-title">Contributions</h3>
|
|
<span class="streak-info"><span class="icon">🔥</span> {{ streak.current }} day streak · Longest {{ streak.longest }}</span>
|
|
</div>
|
|
<div class="heatmap-grid">
|
|
{% for week in heatmap %}
|
|
<div class="heatmap-week">
|
|
{% for day in week %}
|
|
<span class="heatmap-cell level-{{ day.level }}" title="{{ day.count }} on {{ day.date }}"></span>
|
|
{% endfor %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="profile-tabs">
|
|
<a href="/profile/{{ profile_user['username'] }}?tab=posts" class="profile-tab {% if current_tab == 'posts' %}active{% endif %}"><span class="icon">📝</span> Posts</a>
|
|
<a href="/profile/{{ profile_user['username'] }}?tab=projects" class="profile-tab {% if current_tab == 'projects' %}active{% endif %}"><span class="icon">🚀</span> Projects</a>
|
|
<a href="/profile/{{ profile_user['username'] }}?tab=gists" class="profile-tab {% if current_tab == 'gists' %}active{% endif %}"><span class="icon">📝</span> Gists</a>
|
|
<a href="/profile/{{ profile_user['username'] }}?tab=activity" class="profile-tab {% if current_tab == 'activity' %}active{% endif %}"><span class="icon">📊</span> Activity</a>
|
|
<button class="btn-ghost btn-icon profile-tab-btn">△</button>
|
|
</div>
|
|
|
|
<div class="profile-posts">
|
|
{% if current_tab == 'posts' %}
|
|
{% for item in posts %}
|
|
{% set _author = profile_user %}{% set _time = item.time_ago %}{% set _show_share = false %}{% set _show_comment_form = false %}{% include "_post_card.html" %}
|
|
{% else %}
|
|
<div class="empty-state">No posts yet.</div>
|
|
{% endfor %}
|
|
{% elif current_tab == 'projects' %}
|
|
{% for p in projects %}
|
|
<a href="/projects/{{ p['slug'] or p['uid'] }}" class="project-card">
|
|
<div class="project-card-header">
|
|
<h3 class="project-card-title">{{ p['title'] }}</h3>
|
|
</div>
|
|
<div class="project-card-meta">
|
|
<span class="project-status {% if p.get('status') == 'Released' %}released{% else %}dev{% endif %}">
|
|
● {{ p.get('status', 'In Development') }}
|
|
</span>
|
|
<span>{{ p.get('project_type', 'software')|replace('_', ' ')|capitalize }}</span>
|
|
</div>
|
|
<div class="project-card-desc rendered-content" data-render>{{ p.get('description', '')[:200] }}</div>
|
|
{% if p.get('platforms') %}
|
|
<div class="project-card-platforms">
|
|
{% for plat in p['platforms'].split(',') %}
|
|
<span class="platform-tag">{{ plat.strip() }}</span>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</a>
|
|
{% else %}
|
|
<div class="empty-state">No projects yet.</div>
|
|
{% endfor %}
|
|
{% elif current_tab == 'gists' %}
|
|
{% for entry in gists %}
|
|
{% set g = entry.gist %}
|
|
<a href="/gists/{{ g['slug'] or g['uid'] }}" class="gist-card">
|
|
<div class="gist-card-header">
|
|
<h3 class="gist-card-title">{{ g['title'] }}</h3>
|
|
<span class="gist-card-star">☆ {{ g.get('stars', 0) }}</span>
|
|
</div>
|
|
<div class="gist-card-meta">
|
|
<span class="gist-language-badge">📝 {{ language_name(g['language']) }}</span>
|
|
</div>
|
|
{% if g.get('description') %}
|
|
<div class="gist-card-desc">{{ g['description'][:200] }}{% if g['description']|length > 200 %}...{% endif %}</div>
|
|
{% endif %}
|
|
<div class="gist-card-footer">
|
|
<span>{{ entry.time_ago }}</span>
|
|
</div>
|
|
</a>
|
|
{% else %}
|
|
<div class="empty-state">No gists yet.</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
{% for act in activities %}
|
|
<div class="post-card activity-card">
|
|
<div class="activity-row">
|
|
<span class="activity-icon">
|
|
{% if act['type'] == 'post' %}📝{% else %}💬{% endif %}
|
|
</span>
|
|
<span class="activity-type">
|
|
{% if act['type'] == 'post' %}Posted{% else %}Commented{% endif %}
|
|
</span>
|
|
<span class="activity-time">{{ act['time_ago'] }}</span>
|
|
</div>
|
|
<p class="activity-content">{{ act['content'] }}</p>
|
|
</div>
|
|
{% else %}
|
|
<div class="empty-state">No activity yet.</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|