- Added CompanyRecommendation system - Made company pages public (removed @login_required) - CSS refactor: inline styles instead of external fluent CSS - Added release notes page - Added admin recommendations panel - Company logos (webp format) - Docker compose configuration Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
305 lines
8.1 KiB
HTML
Executable File
305 lines
8.1 KiB
HTML
Executable File
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ topic.title }} - Forum - Norda Biznes Hub{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.topic-breadcrumb {
|
|
margin-bottom: var(--spacing-lg);
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.topic-breadcrumb a {
|
|
color: var(--primary);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.topic-breadcrumb a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.topic-header {
|
|
background: var(--surface);
|
|
border-radius: var(--radius-lg);
|
|
padding: var(--spacing-xl);
|
|
margin-bottom: var(--spacing-xl);
|
|
box-shadow: var(--shadow);
|
|
}
|
|
|
|
.topic-header.pinned {
|
|
border-left: 4px solid var(--primary);
|
|
}
|
|
|
|
.topic-header.locked {
|
|
border-left: 4px solid var(--secondary);
|
|
}
|
|
|
|
.topic-title-row {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: var(--spacing-md);
|
|
margin-bottom: var(--spacing-md);
|
|
}
|
|
|
|
.topic-title {
|
|
font-size: var(--font-size-2xl);
|
|
font-weight: 700;
|
|
color: var(--text-primary);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.topic-badge {
|
|
font-size: var(--font-size-sm);
|
|
padding: 4px 10px;
|
|
border-radius: var(--radius-sm);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.badge-pinned {
|
|
background: var(--primary);
|
|
color: white;
|
|
}
|
|
|
|
.badge-locked {
|
|
background: var(--secondary);
|
|
color: white;
|
|
}
|
|
|
|
.topic-meta {
|
|
display: flex;
|
|
gap: var(--spacing-lg);
|
|
color: var(--text-secondary);
|
|
font-size: var(--font-size-sm);
|
|
margin-bottom: var(--spacing-lg);
|
|
}
|
|
|
|
.topic-meta span {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-xs);
|
|
}
|
|
|
|
.topic-content {
|
|
line-height: 1.8;
|
|
color: var(--text-primary);
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.replies-section {
|
|
margin-top: var(--spacing-xl);
|
|
}
|
|
|
|
.replies-header {
|
|
font-size: var(--font-size-xl);
|
|
font-weight: 600;
|
|
margin-bottom: var(--spacing-lg);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.replies-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--spacing-md);
|
|
}
|
|
|
|
.reply-card {
|
|
background: var(--surface);
|
|
border-radius: var(--radius-lg);
|
|
padding: var(--spacing-lg);
|
|
box-shadow: var(--shadow-sm);
|
|
border-left: 3px solid var(--border);
|
|
}
|
|
|
|
.reply-card:hover {
|
|
border-left-color: var(--primary);
|
|
}
|
|
|
|
.reply-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: var(--spacing-md);
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.reply-author {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
font-weight: 500;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.reply-avatar {
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 50%;
|
|
background: var(--primary);
|
|
color: white;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-weight: 600;
|
|
font-size: var(--font-size-sm);
|
|
}
|
|
|
|
.reply-content {
|
|
line-height: 1.7;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.reply-form {
|
|
background: var(--surface);
|
|
border-radius: var(--radius-lg);
|
|
padding: var(--spacing-xl);
|
|
margin-top: var(--spacing-xl);
|
|
box-shadow: var(--shadow);
|
|
}
|
|
|
|
.reply-form h3 {
|
|
margin-bottom: var(--spacing-lg);
|
|
font-size: var(--font-size-lg);
|
|
}
|
|
|
|
.reply-form textarea {
|
|
width: 100%;
|
|
min-height: 120px;
|
|
padding: var(--spacing-md);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
font-family: var(--font-family);
|
|
font-size: var(--font-size-base);
|
|
resize: vertical;
|
|
margin-bottom: var(--spacing-md);
|
|
}
|
|
|
|
.reply-form textarea:focus {
|
|
outline: none;
|
|
border-color: var(--primary);
|
|
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
|
}
|
|
|
|
.locked-notice {
|
|
background: #fef3c7;
|
|
border: 1px solid #f59e0b;
|
|
border-radius: var(--radius);
|
|
padding: var(--spacing-md);
|
|
margin-top: var(--spacing-xl);
|
|
text-align: center;
|
|
color: #92400e;
|
|
}
|
|
|
|
.empty-replies {
|
|
text-align: center;
|
|
padding: var(--spacing-xl);
|
|
color: var(--text-secondary);
|
|
background: var(--background);
|
|
border-radius: var(--radius);
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.topic-title-row {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.topic-meta {
|
|
flex-wrap: wrap;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<nav class="topic-breadcrumb">
|
|
<a href="{{ url_for('forum_index') }}">Forum</a> » {{ topic.title[:50] }}{% if topic.title|length > 50 %}...{% endif %}
|
|
</nav>
|
|
|
|
<article class="topic-header {% if topic.is_pinned %}pinned{% endif %} {% if topic.is_locked %}locked{% endif %}">
|
|
<div class="topic-title-row">
|
|
<h1 class="topic-title">
|
|
{% if topic.is_pinned %}
|
|
<span class="topic-badge badge-pinned">Przypiety</span>
|
|
{% endif %}
|
|
{% if topic.is_locked %}
|
|
<span class="topic-badge badge-locked">Zamkniety</span>
|
|
{% endif %}
|
|
{{ topic.title }}
|
|
</h1>
|
|
</div>
|
|
|
|
<div class="topic-meta">
|
|
<span>
|
|
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
|
<circle cx="12" cy="7" r="4"></circle>
|
|
</svg>
|
|
{{ topic.author.name or topic.author.email.split('@')[0] }}
|
|
</span>
|
|
<span>
|
|
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
<circle cx="12" cy="12" r="10"></circle>
|
|
<polyline points="12 6 12 12 16 14"></polyline>
|
|
</svg>
|
|
{{ topic.created_at.strftime('%d.%m.%Y %H:%M') }}
|
|
</span>
|
|
<span>
|
|
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
|
|
<circle cx="12" cy="12" r="3"></circle>
|
|
</svg>
|
|
{{ topic.views_count }} wyswietlen
|
|
</span>
|
|
</div>
|
|
|
|
<div class="topic-content">{{ topic.content }}</div>
|
|
</article>
|
|
|
|
<section class="replies-section">
|
|
<h2 class="replies-header">
|
|
Odpowiedzi ({{ topic.replies|length }})
|
|
</h2>
|
|
|
|
{% if topic.replies %}
|
|
<div class="replies-list">
|
|
{% for reply in topic.replies %}
|
|
<article class="reply-card">
|
|
<div class="reply-header">
|
|
<div class="reply-author">
|
|
<div class="reply-avatar">
|
|
{{ (reply.author.name or reply.author.email)[0].upper() }}
|
|
</div>
|
|
{{ reply.author.name or reply.author.email.split('@')[0] }}
|
|
</div>
|
|
<span>{{ reply.created_at.strftime('%d.%m.%Y %H:%M') }}</span>
|
|
</div>
|
|
<div class="reply-content">{{ reply.content }}</div>
|
|
</article>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="empty-replies">
|
|
Brak odpowiedzi. Badz pierwszy!
|
|
</div>
|
|
{% endif %}
|
|
</section>
|
|
|
|
{% if topic.is_locked %}
|
|
<div class="locked-notice">
|
|
Ten temat jest zamkniety. Nie mozna dodawac nowych odpowiedzi.
|
|
</div>
|
|
{% else %}
|
|
<form class="reply-form" method="POST" action="{{ url_for('forum_reply', topic_id=topic.id) }}">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<h3>Dodaj odpowiedz</h3>
|
|
<textarea name="content" placeholder="Twoja odpowiedz..." required></textarea>
|
|
<button type="submit" class="btn btn-primary">Wyslij odpowiedz</button>
|
|
</form>
|
|
{% endif %}
|
|
{% endblock %}
|