Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
5d97576544
|
|||
d16b88a499
|
|||
4df7f72312
|
|||
af28cefba0
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ailog"
|
||||
version = "0.1.7"
|
||||
version = "0.1.6"
|
||||
edition = "2021"
|
||||
authors = ["syui"]
|
||||
description = "A static blog generator with AI features"
|
||||
|
Binary file not shown.
@ -1,3 +1,3 @@
|
||||
<!-- OAuth Comment System - Load globally for session management -->
|
||||
<script type="module" crossorigin src="/assets/comment-atproto-mfW-OeY_.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/comment-atproto-Cm5qR-aM.css">
|
||||
<script type="module" crossorigin src="/assets/comment-atproto-C3utAhPv.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/comment-atproto-BH-72ESb.css">
|
@ -262,8 +262,8 @@ function setupAskAIEventListeners() {
|
||||
}
|
||||
}
|
||||
|
||||
// Enter key to send message (only when not composing Japanese input)
|
||||
if (e.key === 'Enter' && e.target.id === 'aiQuestion' && !e.shiftKey && !e.isComposing) {
|
||||
// Enter key to send message
|
||||
if (e.key === 'Enter' && e.target.id === 'aiQuestion' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
askQuestion();
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
<!-- OAuth Comment System - Load globally for session management -->
|
||||
<script type="module" crossorigin src="/assets/comment-atproto-mfW-OeY_.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/comment-atproto-Cm5qR-aM.css">
|
||||
<script type="module" crossorigin src="/assets/comment-atproto-C3utAhPv.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/comment-atproto-BH-72ESb.css">
|
@ -499,8 +499,9 @@
|
||||
}
|
||||
|
||||
.comments-list {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 0px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.comments-header {
|
||||
@ -859,6 +860,28 @@
|
||||
background: #f6f8fa;
|
||||
}
|
||||
|
||||
/* AI Chat History */
|
||||
.ai-chat-list {
|
||||
max-width: 100%;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.chat-item {
|
||||
border: 1px solid #d1d9e0;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.chat-actions {
|
||||
display: flex;
|
||||
@ -910,7 +933,3 @@
|
||||
color: #656d76;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.chat-message.comment-style {
|
||||
border-left: 4px solid var(--theme-color);
|
||||
}
|
@ -259,8 +259,8 @@ function App() {
|
||||
if (appConfig.rkey) {
|
||||
// On post page: show only chats for this specific post
|
||||
filteredRecords = allChatRecords.filter(record => {
|
||||
const recordRkey = record.value.post?.url ? new URL(record.value.post.url).pathname.split('/').pop()?.replace(/\.html$/, '') : '';
|
||||
return recordRkey === appConfig.rkey;
|
||||
const recordPath = record.value.post?.url ? new URL(record.value.post.url).pathname : '';
|
||||
return recordPath === window.location.pathname;
|
||||
});
|
||||
} else {
|
||||
// On top page: show latest 3 records from all pages
|
||||
@ -302,12 +302,13 @@ function App() {
|
||||
const langData = await langResponse.json();
|
||||
const langRecords = langData.records || [];
|
||||
|
||||
// Filter by current page rkey if on post page
|
||||
// Filter by current page path if on post page
|
||||
const filteredLangRecords = appConfig.rkey
|
||||
? langRecords.filter(record => {
|
||||
// Compare rkey only (last part of path)
|
||||
const recordRkey = record.value.post?.url ? new URL(record.value.post.url).pathname.split('/').pop()?.replace(/\.html$/, '') : '';
|
||||
return recordRkey === appConfig.rkey;
|
||||
// Compare path only, not full URL to support localhost vs production
|
||||
const recordPath = record.value.post?.url ? new URL(record.value.post.url).pathname :
|
||||
record.value.url ? new URL(record.value.url).pathname : '';
|
||||
return recordPath === window.location.pathname;
|
||||
})
|
||||
: langRecords.slice(0, 3); // Top page: latest 3
|
||||
|
||||
@ -320,12 +321,13 @@ function App() {
|
||||
const commentData = await commentResponse.json();
|
||||
const commentRecords = commentData.records || [];
|
||||
|
||||
// Filter by current page rkey if on post page
|
||||
// Filter by current page path if on post page
|
||||
const filteredCommentRecords = appConfig.rkey
|
||||
? commentRecords.filter(record => {
|
||||
// Compare rkey only (last part of path)
|
||||
const recordRkey = record.value.post?.url ? new URL(record.value.post.url).pathname.split('/').pop()?.replace(/\.html$/, '') : '';
|
||||
return recordRkey === appConfig.rkey;
|
||||
// Compare path only, not full URL to support localhost vs production
|
||||
const recordPath = record.value.post?.url ? new URL(record.value.post.url).pathname :
|
||||
record.value.url ? new URL(record.value.url).pathname : '';
|
||||
return recordPath === window.location.pathname;
|
||||
})
|
||||
: commentRecords.slice(0, 3); // Top page: latest 3
|
||||
|
||||
@ -538,14 +540,16 @@ function App() {
|
||||
|
||||
|
||||
// ページpathでフィルタリング(指定された場合)
|
||||
const filteredComments = pageUrl && appConfig.rkey
|
||||
const filteredComments = pageUrl
|
||||
? userComments.filter(record => {
|
||||
try {
|
||||
// Compare rkey only (last part of path)
|
||||
const recordRkey = record.value.url ? new URL(record.value.url).pathname.split('/').pop() : '';
|
||||
return recordRkey === appConfig.rkey;
|
||||
// Compare path only, not full URL to support localhost vs production
|
||||
const recordPath = record.value.url ? new URL(record.value.url).pathname : '';
|
||||
const currentPath = new URL(pageUrl).pathname;
|
||||
return recordPath === currentPath;
|
||||
} catch (err) {
|
||||
return false;
|
||||
// Fallback to exact match if URL parsing fails
|
||||
return record.value.url === pageUrl;
|
||||
}
|
||||
})
|
||||
: userComments;
|
||||
@ -1049,8 +1053,6 @@ function App() {
|
||||
<div className="username-input-section">
|
||||
<input
|
||||
type="text"
|
||||
id="handle-input"
|
||||
name="handle"
|
||||
placeholder="user.bsky.social"
|
||||
className="handle-input"
|
||||
value={handleInput}
|
||||
@ -1092,8 +1094,6 @@ function App() {
|
||||
{/* User List Form */}
|
||||
<div className="user-list-form">
|
||||
<textarea
|
||||
id="user-list-input"
|
||||
name="userList"
|
||||
value={userListInput}
|
||||
onChange={(e) => setUserListInput(e.target.value)}
|
||||
placeholder="ユーザーハンドルをカンマ区切りで入力 例: syui.ai, yui.syui.ai, user.bsky.social"
|
||||
@ -1188,13 +1188,13 @@ function App() {
|
||||
className={`tab-button ${activeTab === 'ai-chat' ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab('ai-chat')}
|
||||
>
|
||||
AI Chat ({aiChatHistory.length})
|
||||
AI Chat History ({aiChatHistory.length})
|
||||
</button>
|
||||
<button
|
||||
className={`tab-button ${activeTab === 'lang-en' ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab('lang-en')}
|
||||
>
|
||||
AI Lang:en ({langEnRecords.length})
|
||||
Lang: EN ({langEnRecords.length})
|
||||
</button>
|
||||
<button
|
||||
className={`tab-button ${activeTab === 'ai-comment' ? 'active' : ''}`}
|
||||
@ -1304,7 +1304,10 @@ function App() {
|
||||
|
||||
{/* AI Chat History List */}
|
||||
{activeTab === 'ai-chat' && (
|
||||
<div className="comments-list">
|
||||
<div className="ai-chat-list">
|
||||
<div className="chat-header">
|
||||
<h3>AI Chat History</h3>
|
||||
</div>
|
||||
{aiChatHistory.length === 0 ? (
|
||||
<p className="no-chat">No AI conversations yet. Start chatting with Ask AI!</p>
|
||||
) : (
|
||||
@ -1316,8 +1319,8 @@ function App() {
|
||||
const displayName = isAiResponse ? 'AI' : (record.value.author?.displayName || record.value.author?.handle);
|
||||
|
||||
return (
|
||||
<div key={index} className="comment-item">
|
||||
<div className="comment-header">
|
||||
<div key={index} className="chat-item">
|
||||
<div className="chat-header">
|
||||
<img
|
||||
src={generatePlaceholderAvatar(displayHandle || 'unknown')}
|
||||
alt={isAiResponse ? "AI Avatar" : "User Avatar"}
|
||||
@ -1401,7 +1404,7 @@ function App() {
|
||||
|
||||
{/* Lang: EN List */}
|
||||
{activeTab === 'lang-en' && (
|
||||
<div className="comments-list">
|
||||
<div className="lang-en-list">
|
||||
{langEnRecords.length === 0 ? (
|
||||
<p className="no-content">No English translations yet</p>
|
||||
) : (
|
||||
@ -1493,12 +1496,11 @@ function App() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Comment Form - Only show on post pages when Comments tab is active */}
|
||||
{user && appConfig.rkey && activeTab === 'comments' && (
|
||||
{/* Comment Form - Only show on post pages */}
|
||||
{user && appConfig.rkey && (
|
||||
<div className="comment-form">
|
||||
<h3>Post a Comment</h3>
|
||||
<textarea
|
||||
id="comment-text"
|
||||
name="commentText"
|
||||
value={commentText}
|
||||
onChange={(e) => setCommentText(e.target.value)}
|
||||
placeholder="Write your comment..."
|
||||
|
@ -62,15 +62,11 @@ function generateBaseCollectionFromHost(host: string): string {
|
||||
}
|
||||
|
||||
// Extract rkey from current URL
|
||||
// /posts/xxx -> xxx (remove .html if present)
|
||||
// /posts/xxx -> xxx
|
||||
function extractRkeyFromUrl(): string | undefined {
|
||||
const pathname = window.location.pathname;
|
||||
const match = pathname.match(/\/posts\/([^/]+)\/?$/);
|
||||
if (match) {
|
||||
// Remove .html extension if present
|
||||
return match[1].replace(/\.html$/, '');
|
||||
}
|
||||
return undefined;
|
||||
return match ? match[1] : undefined;
|
||||
}
|
||||
|
||||
// Get application configuration from environment variables
|
||||
|
Reference in New Issue
Block a user