- Zmiana nazwy: "Norda Biznes Hub" → "Norda Biznes Partner" - Aktualizacja modelu AI: Gemini 2.0 Flash → Gemini 3 Flash - Zachowano historyczne odniesienia w timeline i dokumentacji Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
515 lines
16 KiB
HTML
515 lines
16 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ announcement.title }} - Aktualnosci - Norda Biznes Partner{% endblock %}
|
|
|
|
{% block meta_description %}{{ announcement.excerpt or announcement.content|striptags|truncate(160) }}{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.back-link {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: var(--spacing-xs);
|
|
color: var(--text-secondary);
|
|
text-decoration: none;
|
|
font-size: var(--font-size-sm);
|
|
margin-bottom: var(--spacing-lg);
|
|
}
|
|
|
|
.back-link:hover {
|
|
color: var(--primary);
|
|
}
|
|
|
|
.announcement-layout {
|
|
display: grid;
|
|
grid-template-columns: 1fr 300px;
|
|
gap: var(--spacing-2xl);
|
|
}
|
|
|
|
@media (max-width: 992px) {
|
|
.announcement-layout {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
|
|
.announcement-main {
|
|
background: var(--surface);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.announcement-header {
|
|
padding: var(--spacing-xl);
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
|
|
.announcement-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-md);
|
|
margin-bottom: var(--spacing-md);
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.category-badge {
|
|
display: inline-block;
|
|
padding: var(--spacing-xs) var(--spacing-sm);
|
|
border-radius: var(--radius-sm);
|
|
font-size: var(--font-size-sm);
|
|
font-weight: 600;
|
|
background: var(--primary-bg);
|
|
color: var(--primary);
|
|
}
|
|
|
|
.category-event { background: #e0f2fe; color: #0369a1; }
|
|
.category-opportunity { background: #dcfce7; color: #15803d; }
|
|
.category-member_news { background: #fef3c7; color: #b45309; }
|
|
.category-partnership { background: #f3e8ff; color: #7c3aed; }
|
|
|
|
.meta-date {
|
|
color: var(--text-secondary);
|
|
font-size: var(--font-size-sm);
|
|
}
|
|
|
|
.meta-views {
|
|
color: var(--text-muted);
|
|
font-size: var(--font-size-sm);
|
|
}
|
|
|
|
.meta-author {
|
|
color: var(--text-secondary);
|
|
font-size: var(--font-size-sm);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.announcement-title {
|
|
font-size: var(--font-size-3xl);
|
|
font-weight: 700;
|
|
color: var(--text-primary);
|
|
line-height: 1.2;
|
|
margin-bottom: var(--spacing-md);
|
|
}
|
|
|
|
.announcement-excerpt {
|
|
font-size: var(--font-size-lg);
|
|
color: var(--text-secondary);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.announcement-image {
|
|
width: 100%;
|
|
max-height: 400px;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.announcement-content {
|
|
padding: var(--spacing-xl);
|
|
}
|
|
|
|
.announcement-content p {
|
|
margin-bottom: var(--spacing-md);
|
|
line-height: 1.8;
|
|
}
|
|
|
|
.announcement-content h3 {
|
|
margin-top: var(--spacing-xl);
|
|
margin-bottom: var(--spacing-md);
|
|
font-size: var(--font-size-xl);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.announcement-content ul, .announcement-content ol {
|
|
margin-bottom: var(--spacing-md);
|
|
padding-left: var(--spacing-xl);
|
|
}
|
|
|
|
.announcement-content li {
|
|
margin-bottom: var(--spacing-sm);
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.announcement-content a {
|
|
color: var(--primary);
|
|
}
|
|
|
|
.announcement-content a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.external-link-box {
|
|
background: var(--primary-bg);
|
|
border: 1px solid var(--primary);
|
|
border-radius: var(--radius-lg);
|
|
padding: var(--spacing-lg);
|
|
margin: var(--spacing-xl) 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: var(--spacing-md);
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.external-link-box .link-text {
|
|
font-weight: 500;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.external-link-box .btn {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.sidebar {
|
|
position: sticky;
|
|
top: var(--spacing-xl);
|
|
}
|
|
|
|
.sidebar-section {
|
|
background: var(--surface);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow);
|
|
padding: var(--spacing-lg);
|
|
margin-bottom: var(--spacing-lg);
|
|
}
|
|
|
|
.sidebar-title {
|
|
font-size: var(--font-size-lg);
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
margin-bottom: var(--spacing-md);
|
|
padding-bottom: var(--spacing-sm);
|
|
border-bottom: 2px solid var(--primary);
|
|
}
|
|
|
|
.other-announcement {
|
|
padding: var(--spacing-md) 0;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
|
|
.other-announcement:last-child {
|
|
border-bottom: none;
|
|
padding-bottom: 0;
|
|
}
|
|
|
|
.other-announcement:first-child {
|
|
padding-top: 0;
|
|
}
|
|
|
|
.other-announcement a {
|
|
color: var(--text-primary);
|
|
text-decoration: none;
|
|
font-weight: 500;
|
|
line-height: 1.4;
|
|
display: block;
|
|
}
|
|
|
|
.other-announcement a:hover {
|
|
color: var(--primary);
|
|
}
|
|
|
|
.other-announcement .date {
|
|
font-size: var(--font-size-xs);
|
|
color: var(--text-muted);
|
|
margin-top: var(--spacing-xs);
|
|
}
|
|
|
|
.share-buttons {
|
|
display: flex;
|
|
gap: var(--spacing-sm);
|
|
}
|
|
|
|
.share-btn {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: var(--radius);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-decoration: none;
|
|
font-size: 1.2em;
|
|
transition: transform 0.2s ease;
|
|
}
|
|
|
|
.share-btn:hover {
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.share-btn.facebook { background: #1877f2; color: white; }
|
|
.share-btn.linkedin { background: #0a66c2; color: white; }
|
|
.share-btn.twitter { background: #1da1f2; color: white; }
|
|
.share-btn.copy { background: var(--surface-secondary); color: var(--text-primary); border: 1px solid var(--border); }
|
|
|
|
.pinned-notice {
|
|
background: linear-gradient(135deg, var(--primary-bg) 0%, var(--surface) 100%);
|
|
border: 1px solid var(--primary);
|
|
border-radius: var(--radius);
|
|
padding: var(--spacing-sm) var(--spacing-md);
|
|
margin-bottom: var(--spacing-lg);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
font-size: var(--font-size-sm);
|
|
color: var(--primary);
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* Seen by section */
|
|
.seen-by-section {
|
|
margin-top: var(--spacing-xl);
|
|
padding-top: var(--spacing-lg);
|
|
border-top: 1px solid var(--border);
|
|
}
|
|
|
|
.seen-by-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: var(--spacing-md);
|
|
}
|
|
|
|
.seen-by-title {
|
|
font-size: var(--font-size-sm);
|
|
font-weight: 600;
|
|
color: var(--text-secondary);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-xs);
|
|
}
|
|
|
|
.seen-by-stats {
|
|
font-size: var(--font-size-xs);
|
|
color: var(--text-muted);
|
|
background: var(--background);
|
|
padding: var(--spacing-xs) var(--spacing-sm);
|
|
border-radius: var(--radius-full);
|
|
}
|
|
|
|
.seen-by-avatars {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--spacing-xs);
|
|
}
|
|
|
|
.reader-avatar {
|
|
width: 36px;
|
|
height: 36px;
|
|
border-radius: 50%;
|
|
background: var(--primary);
|
|
color: white;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: var(--font-size-sm);
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
position: relative;
|
|
}
|
|
|
|
.reader-avatar:hover {
|
|
transform: scale(1.1);
|
|
box-shadow: var(--shadow-md);
|
|
z-index: 10;
|
|
}
|
|
|
|
.reader-avatar[data-tooltip]:hover::after {
|
|
content: attr(data-tooltip);
|
|
position: absolute;
|
|
bottom: 100%;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
background: var(--text-primary);
|
|
color: white;
|
|
padding: var(--spacing-xs) var(--spacing-sm);
|
|
border-radius: var(--radius-sm);
|
|
font-size: var(--font-size-xs);
|
|
white-space: nowrap;
|
|
margin-bottom: 4px;
|
|
z-index: 100;
|
|
}
|
|
|
|
.reader-avatar.more {
|
|
background: var(--surface-secondary);
|
|
color: var(--text-secondary);
|
|
border: 1px solid var(--border);
|
|
}
|
|
|
|
.progress-bar-container {
|
|
width: 100%;
|
|
height: 6px;
|
|
background: var(--border);
|
|
border-radius: 3px;
|
|
margin-top: var(--spacing-sm);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress-bar-fill {
|
|
height: 100%;
|
|
background: linear-gradient(90deg, var(--primary) 0%, var(--success) 100%);
|
|
border-radius: 3px;
|
|
transition: width 0.5s ease;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container">
|
|
<a href="{{ url_for('announcements_list') }}" class="back-link">
|
|
← Powrot do listy ogloszen
|
|
</a>
|
|
|
|
{% if announcement.is_pinned %}
|
|
<div class="pinned-notice">
|
|
📌 To ogloszenie jest przypiete i wyswietla sie na gorze listy
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="announcement-layout">
|
|
<!-- Main content -->
|
|
<article class="announcement-main">
|
|
<div class="announcement-header">
|
|
<div class="announcement-meta">
|
|
<span class="category-badge category-{{ announcement.category }}">
|
|
{{ category_labels.get(announcement.category, announcement.category) }}
|
|
</span>
|
|
<span class="meta-date">
|
|
{{ announcement.published_at.strftime('%d %B %Y') if announcement.published_at else '' }}
|
|
</span>
|
|
{% if announcement.author %}
|
|
<span class="meta-author">
|
|
👤 {{ announcement.author.name }}
|
|
</span>
|
|
{% endif %}
|
|
<span class="meta-views">
|
|
👁 {{ announcement.views_count or 0 }} wyswietlen
|
|
</span>
|
|
</div>
|
|
|
|
<h1 class="announcement-title">{{ announcement.title }}</h1>
|
|
|
|
{% if announcement.excerpt %}
|
|
<p class="announcement-excerpt">{{ announcement.excerpt }}</p>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% if announcement.image_url %}
|
|
<img src="{{ announcement.image_url }}" alt="{{ announcement.title }}" class="announcement-image"
|
|
onerror="this.style.display='none'">
|
|
{% endif %}
|
|
|
|
<div class="announcement-content">
|
|
{{ announcement.content|safe }}
|
|
|
|
{% if announcement.external_link %}
|
|
<div class="external-link-box">
|
|
<div class="link-text">
|
|
🌐 Wiecej informacji znajdziesz na zewnetrznej stronie
|
|
</div>
|
|
<a href="{{ announcement.external_link }}" target="_blank" rel="noopener noreferrer" class="btn btn-primary">
|
|
Przejdz do strony →
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Seen by section -->
|
|
<div class="seen-by-section">
|
|
<div class="seen-by-header">
|
|
<div class="seen-by-title">
|
|
👁 Przeczytane przez
|
|
</div>
|
|
<div class="seen-by-stats">
|
|
{{ readers_count }} z {{ total_users }} ({{ read_percentage }}%)
|
|
</div>
|
|
</div>
|
|
|
|
<div class="seen-by-avatars">
|
|
{% for read in readers[:20] %}
|
|
<div class="reader-avatar"
|
|
data-tooltip="{{ read.user.name or read.user.email.split('@')[0] }}{% if loop.first %} (Ty){% endif %}"
|
|
style="background: hsl({{ (read.user.id * 137) % 360 }}, 65%, 50%);">
|
|
{{ (read.user.name or read.user.email)[0]|upper }}
|
|
</div>
|
|
{% endfor %}
|
|
{% if readers_count > 20 %}
|
|
<div class="reader-avatar more" data-tooltip="i {{ readers_count - 20 }} innych">
|
|
+{{ readers_count - 20 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="progress-bar-container">
|
|
<div class="progress-bar-fill" style="width: {{ read_percentage }}%;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
<!-- Sidebar -->
|
|
<aside class="sidebar">
|
|
<!-- Share -->
|
|
<div class="sidebar-section">
|
|
<h3 class="sidebar-title">Udostepnij</h3>
|
|
<div class="share-buttons">
|
|
<a href="https://www.facebook.com/sharer/sharer.php?u={{ request.url|urlencode }}"
|
|
target="_blank" rel="noopener" class="share-btn facebook" title="Udostepnij na Facebooku">
|
|
f
|
|
</a>
|
|
<a href="https://www.linkedin.com/sharing/share-offsite/?url={{ request.url|urlencode }}"
|
|
target="_blank" rel="noopener" class="share-btn linkedin" title="Udostepnij na LinkedIn">
|
|
in
|
|
</a>
|
|
<a href="https://twitter.com/intent/tweet?url={{ request.url|urlencode }}&text={{ announcement.title|urlencode }}"
|
|
target="_blank" rel="noopener" class="share-btn twitter" title="Udostepnij na Twitterze">
|
|
X
|
|
</a>
|
|
<button class="share-btn copy" title="Kopiuj link" onclick="copyLink()">
|
|
🔗
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Other announcements -->
|
|
{% if other_announcements %}
|
|
<div class="sidebar-section">
|
|
<h3 class="sidebar-title">Inne ogloszenia</h3>
|
|
{% for other in other_announcements %}
|
|
<div class="other-announcement">
|
|
<a href="{{ url_for('announcement_detail', slug=other.slug) }}">
|
|
{{ other.title }}
|
|
</a>
|
|
<div class="date">
|
|
{{ other.published_at.strftime('%d.%m.%Y') if other.published_at else '' }}
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Back to list -->
|
|
<div class="sidebar-section" style="text-align: center;">
|
|
<a href="{{ url_for('announcements_list') }}" class="btn btn-secondary" style="width: 100%;">
|
|
← Wszystkie ogloszenia
|
|
</a>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
function copyLink() {
|
|
navigator.clipboard.writeText(window.location.href).then(function() {
|
|
const btn = document.querySelector('.share-btn.copy');
|
|
const originalText = btn.innerHTML;
|
|
btn.innerHTML = '✓';
|
|
btn.style.background = 'var(--success-bg)';
|
|
btn.style.color = 'var(--success)';
|
|
setTimeout(function() {
|
|
btn.innerHTML = originalText;
|
|
btn.style.background = '';
|
|
btn.style.color = '';
|
|
}, 2000);
|
|
});
|
|
}
|
|
{% endblock %}
|