ui: 导航圆润与用户信息展示;详情页作者与关注;主页粉丝/关注与卡片网格
This commit is contained in:
@@ -1,14 +1,23 @@
|
||||
from flask import Blueprint, render_template, request, redirect, url_for
|
||||
from flask_login import login_required, current_user
|
||||
from ..extensions import db
|
||||
from ..models import User, Profile, Notification
|
||||
from ..models import User, Profile, Notification, Follow
|
||||
|
||||
bp = Blueprint("users", __name__, url_prefix="/users")
|
||||
|
||||
@bp.route("/<int:user_id>")
|
||||
def profile(user_id):
|
||||
user = User.query.get_or_404(user_id)
|
||||
return render_template("users/profile.html", user=user)
|
||||
followers_count = Follow.query.filter_by(followee_id=user.id).count()
|
||||
following_count = Follow.query.filter_by(follower_id=user.id).count()
|
||||
is_following = False
|
||||
try:
|
||||
from flask_login import current_user
|
||||
if current_user.is_authenticated:
|
||||
is_following = Follow.query.filter_by(follower_id=current_user.id, followee_id=user.id).first() is not None
|
||||
except Exception:
|
||||
pass
|
||||
return render_template("users/profile.html", user=user, followers_count=followers_count, following_count=following_count, is_following=is_following)
|
||||
|
||||
@bp.route("/me/edit", methods=["GET", "POST"])
|
||||
@login_required
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
body { background: #f8fafc; }
|
||||
.container { max-width: 1100px; }
|
||||
.navbar { border-radius: var(--radius); box-shadow: var(--shadow); }
|
||||
.nav-menu a { padding: 8px 14px; border-radius: 999px; }
|
||||
.nav-menu a:hover { background: #f1f5ff; }
|
||||
.nav-user { display:flex; align-items:center; gap:12px; }
|
||||
.avatar { width: 32px; height: 32px; border-radius: 50%; background: #e5e7eb; display:inline-flex; align-items:center; justify-content:center; font-weight:600; color:#4b5563; }
|
||||
.card { border: 0; border-radius: var(--radius); box-shadow: var(--shadow); }
|
||||
.btn { border-radius: var(--radius-sm); }
|
||||
.form-control, .form-select, textarea { border-radius: var(--radius-sm); }
|
||||
|
||||
@@ -11,22 +11,29 @@
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-white mb-3 mt-2 px-3">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="{{ url_for('feed.discover') }}">摄影社</a>
|
||||
<div>
|
||||
<a class="btn btn-link" href="{{ url_for('feed.discover') }}">发现</a>
|
||||
{% if current_user.is_authenticated %}
|
||||
<a class="btn btn-link" href="{{ url_for('feed.following') }}">关注</a>
|
||||
<a class="btn btn-link" href="{{ url_for('users.profile', user_id=current_user.id) }}">我的主页</a>
|
||||
<a class="btn btn-link" href="{{ url_for('users.notifications') }}">通知</a>
|
||||
<a class="btn btn-link" href="{{ url_for('posts.create') }}">发布作品</a>
|
||||
<a class="btn btn-link" href="{{ url_for('activities.list_activities') }}">活动</a>
|
||||
{% if current_user.role == 'admin' %}
|
||||
<a class="btn btn-link" href="{{ url_for('admin.dashboard') }}">管理员</a>
|
||||
{% endif %}
|
||||
<a class="btn btn-link" href="{{ url_for('auth.logout') }}">退出</a>
|
||||
{% else %}
|
||||
<a class="btn btn-link" href="{{ url_for('auth.login') }}">登录</a>
|
||||
<a class="btn btn-brand" href="{{ url_for('auth.register') }}">注册</a>
|
||||
{% endif %}
|
||||
<div class="d-flex justify-content-between align-items-center w-100">
|
||||
<div class="nav-menu">
|
||||
<a class="btn btn-link" href="{{ url_for('feed.discover') }}">发现</a>
|
||||
{% if current_user.is_authenticated %}
|
||||
<a class="btn btn-link" href="{{ url_for('feed.following') }}">关注</a>
|
||||
<a class="btn btn-link" href="{{ url_for('activities.list_activities') }}">活动</a>
|
||||
{% if current_user.role in ['admin','sub_admin','checker'] %}
|
||||
<a class="btn btn-link" href="{{ url_for('admin.dashboard') }}">后台</a>
|
||||
{% endif %}
|
||||
<a class="btn btn-brand" href="{{ url_for('posts.create') }}">发布作品</a>
|
||||
{% else %}
|
||||
<a class="btn btn-link" href="{{ url_for('auth.login') }}">登录</a>
|
||||
<a class="btn btn-brand" href="{{ url_for('auth.register') }}">注册</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="nav-user">
|
||||
{% if current_user.is_authenticated %}
|
||||
<span class="avatar">{{ current_user.username[:1]|upper }}</span>
|
||||
<a class="btn btn-link" href="{{ url_for('users.profile', user_id=current_user.id) }}">{{ current_user.username }}</a>
|
||||
<a class="btn btn-link" href="{{ url_for('users.notifications') }}">通知</a>
|
||||
<a class="btn btn-link" href="{{ url_for('auth.logout') }}">退出</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -3,7 +3,18 @@
|
||||
{% block content %}
|
||||
<div class="card mb-3">
|
||||
<div class="p-3">
|
||||
<h3 class="mb-2">{{ post.title }}</h3>
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<span class="avatar">{{ post.user.username[:1]|upper }}</span>
|
||||
<div>
|
||||
<h3 class="mb-1">{{ post.title }}</h3>
|
||||
<a class="text-decoration-none" href="{{ url_for('users.profile', user_id=post.user.id) }}">{{ post.user.username }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% if current_user.is_authenticated and current_user.id != post.user.id %}
|
||||
<a class="btn btn-brand" href="{{ url_for('follows.follow', user_id=post.user.id) }}">关注作者</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="text-secondary">{{ post.description }}</p>
|
||||
<span class="badge bg-light text-dark">{{ post.visibility.value }}</span>
|
||||
</div>
|
||||
|
||||
@@ -1,19 +1,37 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}主页{% endblock %}
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h3>{{ user.username }}</h3>
|
||||
{% if current_user.is_authenticated and current_user.id != user.id %}
|
||||
<a class="btn btn-outline-primary" href="{{ url_for('follows.follow', user_id=user.id) }}">关注</a>
|
||||
{% endif %}
|
||||
<div class="card p-3 mb-3">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<span class="avatar">{{ user.username[:1]|upper }}</span>
|
||||
<h3 class="m-0">{{ user.username }}</h3>
|
||||
</div>
|
||||
{% if current_user.is_authenticated and current_user.id != user.id %}
|
||||
{% if is_following %}
|
||||
<a class="btn btn-secondary" href="{{ url_for('follows.unfollow', user_id=user.id) }}">已关注</a>
|
||||
{% else %}
|
||||
<a class="btn btn-brand" href="{{ url_for('follows.follow', user_id=user.id) }}">关注</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="text-secondary mt-2">粉丝 {{ followers_count }} · 关注 {{ following_count }}</div>
|
||||
<p class="mt-2">{{ user.profile.bio }}</p>
|
||||
</div>
|
||||
<p>{{ user.profile.bio }}</p>
|
||||
<hr>
|
||||
<h5>作品</h5>
|
||||
<div class="row">
|
||||
<h5 class="mb-2">作品</h5>
|
||||
<div class="card-grid">
|
||||
{% for p in user.posts %}
|
||||
<div class="col-md-4">
|
||||
<a href="{{ url_for('posts.detail', post_id=p.id) }}">{{ p.title }}</a>
|
||||
<div class="card">
|
||||
{% set first = p.images[0] if p.images %}
|
||||
{% if first %}
|
||||
<a href="{{ url_for('posts.detail', post_id=p.id) }}">
|
||||
<img class="photo-thumb" src="{{ url_for('main.uploads', filename=first.web_path) }}" alt="{{ p.title }}" />
|
||||
</a>
|
||||
{% endif %}
|
||||
<div class="p-3">
|
||||
<a class="text-decoration-none" href="{{ url_for('posts.detail', post_id=p.id) }}">{{ p.title }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user