196 lines
6.1 KiB
HTML
196 lines
6.1 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ post.title }} - {{ config.title }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="article-container">
|
|
<article class="article-content">
|
|
<header class="article-header">
|
|
<h1 class="article-title">{{ post.title }}</h1>
|
|
<div class="article-meta">
|
|
<time class="article-date">{{ post.date }}</time>
|
|
{% if post.language %}
|
|
<span class="article-lang">{{ post.language }}</span>
|
|
{% endif %}
|
|
</div>
|
|
<div class="article-actions">
|
|
{% if post.markdown_url %}
|
|
<a href="{{ post.markdown_url }}" class="action-btn markdown-btn" title="View Markdown">
|
|
📝 Markdown
|
|
</a>
|
|
{% endif %}
|
|
{% if post.translation_url %}
|
|
<a href="{{ post.translation_url }}" class="action-btn translation-btn" title="View Translation">
|
|
🌐 {% if post.language == 'ja' %}English{% else %}日本語{% endif %}
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</header>
|
|
|
|
<div class="article-body">
|
|
{{ post.content | safe }}
|
|
</div>
|
|
|
|
<!-- Simple Comment Section -->
|
|
<section class="comment-section">
|
|
<div class="comment-container">
|
|
<h3>Comments</h3>
|
|
|
|
<!-- Simple OAuth Button -->
|
|
<div class="simple-oauth">
|
|
<p>📝 To comment, authenticate with Bluesky:</p>
|
|
<button id="bluesky-auth" class="oauth-button">
|
|
🦋 Login with Bluesky
|
|
</button>
|
|
<p class="oauth-note">
|
|
<small>After authentication, you can post comments that will be stored in your ATProto PDS.</small>
|
|
</p>
|
|
</div>
|
|
|
|
<div id="comments-list" class="comments-list">
|
|
<p class="no-comments">Comments will appear here when posted via ATProto.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</article>
|
|
|
|
<aside class="article-sidebar">
|
|
<nav class="toc">
|
|
<h3>Contents</h3>
|
|
<div id="toc-content">
|
|
<!-- TOC will be generated by JavaScript -->
|
|
</div>
|
|
</nav>
|
|
</aside>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block sidebar %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
generateTableOfContents();
|
|
initializeSimpleAuth();
|
|
});
|
|
|
|
function generateTableOfContents() {
|
|
const tocContainer = document.getElementById('toc-content');
|
|
const headings = document.querySelectorAll('.article-body h1, .article-body h2, .article-body h3, .article-body h4, .article-body h5, .article-body h6');
|
|
|
|
if (headings.length === 0) {
|
|
tocContainer.innerHTML = '<p class="no-toc">No headings found</p>';
|
|
return;
|
|
}
|
|
|
|
const tocList = document.createElement('ul');
|
|
tocList.className = 'toc-list';
|
|
|
|
headings.forEach((heading, index) => {
|
|
const id = `heading-${index}`;
|
|
heading.id = id;
|
|
|
|
const listItem = document.createElement('li');
|
|
listItem.className = `toc-item toc-${heading.tagName.toLowerCase()}`;
|
|
|
|
const link = document.createElement('a');
|
|
link.href = `#${id}`;
|
|
link.textContent = heading.textContent;
|
|
link.className = 'toc-link';
|
|
|
|
link.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
heading.scrollIntoView({ behavior: 'smooth' });
|
|
});
|
|
|
|
listItem.appendChild(link);
|
|
tocList.appendChild(listItem);
|
|
});
|
|
|
|
tocContainer.appendChild(tocList);
|
|
}
|
|
|
|
function initializeSimpleAuth() {
|
|
const authButton = document.getElementById('bluesky-auth');
|
|
|
|
authButton.addEventListener('click', function() {
|
|
// Simple approach: Direct redirect to Bluesky OAuth
|
|
const isProduction = window.location.hostname === 'log.syui.ai';
|
|
const clientId = isProduction
|
|
? 'https://log.syui.ai/client-metadata.json'
|
|
: window.location.origin + '/client-metadata.json';
|
|
|
|
const authUrl = `https://bsky.social/oauth/authorize?` +
|
|
`client_id=${encodeURIComponent(clientId)}&` +
|
|
`redirect_uri=${encodeURIComponent(window.location.href)}&` +
|
|
`response_type=code&` +
|
|
`scope=atproto%20transition:generic&` +
|
|
`state=demo-state`;
|
|
|
|
console.log('Redirecting to:', authUrl);
|
|
|
|
// Open in new tab for now (safer for testing)
|
|
window.open(authUrl, '_blank');
|
|
|
|
// Show status message
|
|
authButton.innerHTML = '✅ Check the new tab for authentication';
|
|
authButton.disabled = true;
|
|
});
|
|
|
|
// Check if we're returning from OAuth
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
if (urlParams.has('code')) {
|
|
console.log('OAuth callback detected:', urlParams.get('code'));
|
|
document.querySelector('.simple-oauth').innerHTML = `
|
|
<div class="oauth-success">
|
|
✅ OAuth callback received!<br>
|
|
<small>Code: ${urlParams.get('code')}</small><br>
|
|
<small>In a full implementation, this would exchange the code for tokens.</small>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.simple-oauth {
|
|
background: #f8f9fa;
|
|
border: 1px solid #e9ecef;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin: 20px 0;
|
|
text-align: center;
|
|
}
|
|
|
|
.oauth-button {
|
|
background: #1185fe;
|
|
color: white;
|
|
border: none;
|
|
padding: 12px 24px;
|
|
border-radius: 6px;
|
|
font-size: 16px;
|
|
cursor: pointer;
|
|
margin: 10px 0;
|
|
}
|
|
|
|
.oauth-button:hover {
|
|
background: #0d6efd;
|
|
}
|
|
|
|
.oauth-button:disabled {
|
|
background: #6c757d;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.oauth-note {
|
|
color: #6c757d;
|
|
font-style: italic;
|
|
}
|
|
|
|
.oauth-success {
|
|
background: #d1edff;
|
|
border: 1px solid #b6d7ff;
|
|
border-radius: 4px;
|
|
padding: 15px;
|
|
color: #0c5460;
|
|
}
|
|
</style>
|
|
{% endblock %} |