add comment
This commit is contained in:
132
src/main.ts
132
src/main.ts
@@ -6,11 +6,15 @@ import { mountPostList, mountPostDetail } from './components/posts.js'
|
||||
import { mountHeader } from './components/browser.js'
|
||||
import { mountAtBrowser } from './components/atbrowser.js'
|
||||
import { mountPostForm } from './components/postform.js'
|
||||
import { loadDiscussionPosts } from './components/discussion.js'
|
||||
import { parseRoute, type Route } from './lib/router.js'
|
||||
import { escapeHtml } from './lib/utils.js'
|
||||
import type { AppConfig, Networks } from './types.js'
|
||||
|
||||
let authSession: AuthSession | null = null
|
||||
let config: AppConfig
|
||||
let networks: Networks = {}
|
||||
let browserNetwork: string = '' // Network for AT Browser
|
||||
|
||||
// Browser state
|
||||
let browserMode = false
|
||||
@@ -42,6 +46,39 @@ function renderFooter(handle: string): string {
|
||||
`
|
||||
}
|
||||
|
||||
function renderPdsSelector(): string {
|
||||
const networkKeys = Object.keys(networks)
|
||||
const options = networkKeys.map(key => {
|
||||
const isSelected = key === browserNetwork
|
||||
return `<div class="pds-option ${isSelected ? 'selected' : ''}" data-network="${escapeHtml(key)}">
|
||||
<span class="pds-name">${escapeHtml(key)}</span>
|
||||
<span class="pds-check">✓</span>
|
||||
</div>`
|
||||
}).join('')
|
||||
|
||||
return `
|
||||
<div class="pds-selector" id="pds-selector">
|
||||
<button type="button" class="tab" id="pds-tab">PDS</button>
|
||||
<div class="pds-dropdown" id="pds-dropdown">
|
||||
${options}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
function updatePdsSelector(): void {
|
||||
const dropdown = document.getElementById('pds-dropdown')
|
||||
if (!dropdown) return
|
||||
|
||||
const options = dropdown.querySelectorAll('.pds-option')
|
||||
options.forEach(opt => {
|
||||
const el = opt as HTMLElement
|
||||
const network = el.dataset.network
|
||||
const isSelected = network === browserNetwork
|
||||
el.classList.toggle('selected', isSelected)
|
||||
})
|
||||
}
|
||||
|
||||
function renderTabs(activeTab: 'blog' | 'browser' | 'new', isLoggedIn: boolean): string {
|
||||
let tabs = `
|
||||
<a href="/" class="tab ${activeTab === 'blog' ? 'active' : ''}" id="blog-tab">Blog</a>
|
||||
@@ -52,6 +89,8 @@ function renderTabs(activeTab: 'blog' | 'browser' | 'new', isLoggedIn: boolean):
|
||||
tabs += `<a href="/post" class="tab ${activeTab === 'new' ? 'active' : ''}">Post</a>`
|
||||
}
|
||||
|
||||
tabs += renderPdsSelector()
|
||||
|
||||
return `<div class="mode-tabs">${tabs}</div>`
|
||||
}
|
||||
|
||||
@@ -123,6 +162,12 @@ async function loadBrowserContent(): Promise<void> {
|
||||
const contentEl = document.getElementById('content')
|
||||
if (!contentEl) return
|
||||
|
||||
// Set network config for browser
|
||||
const browserNetworkConfig = networks[browserNetwork]
|
||||
if (browserNetworkConfig) {
|
||||
setNetworkConfig(browserNetworkConfig)
|
||||
}
|
||||
|
||||
const loginDid = authSession?.did || null
|
||||
await mountAtBrowser(
|
||||
contentEl,
|
||||
@@ -217,14 +262,6 @@ async function addEditButtonToStaticPost(collection: string, rkey: string, sessi
|
||||
})
|
||||
}
|
||||
|
||||
function escapeHtml(str: string): string {
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
}
|
||||
|
||||
// Refresh post list from API (for static pages)
|
||||
async function refreshPostListFromAPI(): Promise<void> {
|
||||
const contentEl = document.getElementById('content')
|
||||
@@ -327,6 +364,56 @@ function setupEventHandlers(): void {
|
||||
return
|
||||
}
|
||||
|
||||
// PDS tab button - toggle dropdown
|
||||
if (target.id === 'pds-tab' || target.closest('#pds-tab')) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
const dropdown = document.getElementById('pds-dropdown')
|
||||
if (dropdown) {
|
||||
dropdown.classList.toggle('show')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PDS option selection
|
||||
const pdsOption = target.closest('.pds-option') as HTMLElement
|
||||
if (pdsOption) {
|
||||
e.preventDefault()
|
||||
const selectedNetwork = pdsOption.dataset.network
|
||||
if (selectedNetwork && selectedNetwork !== browserNetwork) {
|
||||
browserNetwork = selectedNetwork
|
||||
localStorage.setItem('browserNetwork', selectedNetwork)
|
||||
|
||||
// Update network config for API
|
||||
const networkConfig = networks[selectedNetwork]
|
||||
if (networkConfig) {
|
||||
setNetworkConfig(networkConfig)
|
||||
}
|
||||
|
||||
// Update UI
|
||||
updatePdsSelector()
|
||||
|
||||
// Reload browser if in browser mode
|
||||
if (browserMode) {
|
||||
loadBrowserContent()
|
||||
}
|
||||
}
|
||||
// Close dropdown
|
||||
const dropdown = document.getElementById('pds-dropdown')
|
||||
if (dropdown) {
|
||||
dropdown.classList.remove('show')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Close PDS dropdown when clicking outside
|
||||
if (!target.closest('#pds-selector')) {
|
||||
const dropdown = document.getElementById('pds-dropdown')
|
||||
if (dropdown) {
|
||||
dropdown.classList.remove('show')
|
||||
}
|
||||
}
|
||||
|
||||
// JSON button click (on post detail page)
|
||||
const jsonBtn = target.closest('.json-btn') as HTMLAnchorElement
|
||||
if (jsonBtn) {
|
||||
@@ -445,6 +532,17 @@ async function render(): Promise<void> {
|
||||
addEditButtonToStaticPost(config.collection, route.rkey, authSession!)
|
||||
}
|
||||
|
||||
// For post pages, load discussion posts
|
||||
if (route.type === 'post') {
|
||||
const discussionContainer = document.getElementById('discussion-posts')
|
||||
if (discussionContainer) {
|
||||
const postUrl = discussionContainer.dataset.postUrl
|
||||
if (postUrl) {
|
||||
loadDiscussionPosts(discussionContainer.parentElement!, postUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For blog top page, check for new posts from API and merge
|
||||
if (route.type === 'blog') {
|
||||
refreshPostListFromAPI()
|
||||
@@ -505,7 +603,7 @@ async function render(): Promise<void> {
|
||||
const post = await getRecord(profile.did, config.collection, route.rkey!)
|
||||
if (post) {
|
||||
const canEdit = isLoggedIn && authSession?.did === profile.did
|
||||
mountPostDetail(contentEl, post, config.handle, config.collection, canEdit)
|
||||
mountPostDetail(contentEl, post, config.handle, config.collection, canEdit, config.siteUrl, config.network)
|
||||
} else {
|
||||
contentEl.innerHTML = '<p>Post not found</p>'
|
||||
}
|
||||
@@ -538,8 +636,9 @@ async function render(): Promise<void> {
|
||||
}
|
||||
|
||||
async function init(): Promise<void> {
|
||||
const [configData, networks] = await Promise.all([loadConfig(), loadNetworks()])
|
||||
const [configData, networksData] = await Promise.all([loadConfig(), loadNetworks()])
|
||||
config = configData
|
||||
networks = networksData
|
||||
|
||||
// Set page title
|
||||
document.title = config.title || 'ailog'
|
||||
@@ -549,11 +648,14 @@ async function init(): Promise<void> {
|
||||
document.documentElement.style.setProperty('--btn-color', config.color)
|
||||
}
|
||||
|
||||
// Set network config
|
||||
const networkConfig = networks[config.network]
|
||||
if (networkConfig) {
|
||||
setNetworkConfig(networkConfig)
|
||||
setAuthNetworkConfig(networkConfig)
|
||||
// Initialize browser network from localStorage or default to config.network
|
||||
browserNetwork = localStorage.getItem('browserNetwork') || config.network
|
||||
|
||||
// Set network config for blog (uses config.network)
|
||||
const blogNetworkConfig = networks[config.network]
|
||||
if (blogNetworkConfig) {
|
||||
setNetworkConfig(blogNetworkConfig)
|
||||
setAuthNetworkConfig(blogNetworkConfig)
|
||||
}
|
||||
|
||||
// Handle OAuth callback
|
||||
|
||||
Reference in New Issue
Block a user