add loader & preview banner

This commit is contained in:
Danilo Znamerovszkij
2025-10-26 17:27:12 +01:00
parent 7ae50fbb1b
commit 9d8385a27c
11 changed files with 316 additions and 170 deletions

1
.gitignore vendored
View File

@@ -11,6 +11,7 @@ node_modules
dist dist
dist-ssr dist-ssr
*.local *.local
/src/data/THEORY.md
# Editor directories and files # Editor directories and files
.vscode/* .vscode/*

View File

@@ -9,7 +9,7 @@
</title> </title>
<meta <meta
name="description" name="description"
content="Explore the ultimate map of the mind. The Consciousness Atlas is a free web app visualizing Robert Kuhn's Landscape of Consciousness—355+ theories of phenomenal consciousness in one interactive chart. Compare theories on AI consciousness, survival after death, and the hard problem of consciousness." content="Explore 300+ theories of consciousness. The Consciousness Atlas is a free web app visualizing Robert Kuhn's Landscape of Consciousness—325+ theories of phenomenal consciousness in one interactive chart. Compare theories on AI consciousness, survival after death, and the hard problem of consciousness."
/> />
<meta <meta
name="keywords" name="keywords"
@@ -22,13 +22,13 @@
/> />
<meta <meta
property="og:description" property="og:description"
content="Explore the ultimate map of the mind. The Consciousness Atlas is a free web app visualizing Robert Kuhn's Landscape of Consciousness—355+ theories of phenomenal consciousness in one interactive chart." content="Explore 300+ theories of consciousness. The Consciousness Atlas is a free web app visualizing Robert Kuhn's Landscape of Consciousness—325+ theories of phenomenal consciousness in one interactive chart."
/> />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:url" content="https://consciousnessatlas.com" /> <meta property="og:url" content="https://consciousnessatlas.com" />
<meta <meta
property="og:image" property="og:image"
content="https://consciousnessatlas.com/logo.png" content="https://consciousnessatlas.com/banner.png"
/> />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta <meta
@@ -37,11 +37,11 @@
/> />
<meta <meta
name="twitter:description" name="twitter:description"
content="Explore the ultimate map of the mind. The Consciousness Atlas is a free web app visualizing Robert Kuhn's Landscape of Consciousness—355+ theories of phenomenal consciousness in one interactive chart." content="Explore the ultimate map of the mind. The Consciousness Atlas is a free web app visualizing Robert Kuhn's Landscape of Consciousness—325+ theories of phenomenal consciousness in one interactive chart."
/> />
<meta <meta
name="twitter:image" name="twitter:image"
content="https://consciousnessatlas.com/logo.png" content="https://consciousnessatlas.com/banner.png"
/> />
<script type="application/ld+json"> <script type="application/ld+json">
@@ -49,7 +49,7 @@
"@context": "https://schema.org", "@context": "https://schema.org",
"@type": "WebApplication", "@type": "WebApplication",
"name": "Consciousness Atlas", "name": "Consciousness Atlas",
"description": "Interactive visualization of 325+ theories from Kuhn's Landscape of Consciousness. Explore the ultimate map of the mind with 355+ theories of phenomenal consciousness in one interactive chart.", "description": "Interactive visualization of 325+ theories from Kuhn's Landscape of Consciousness. Explore the ultimate map of the mind with 325+ theories of phenomenal consciousness in one interactive chart.",
"url": "https://consciousnessatlas.com", "url": "https://consciousnessatlas.com",
"applicationCategory": "EducationalApplication", "applicationCategory": "EducationalApplication",
"operatingSystem": "Web Browser", "operatingSystem": "Web Browser",
@@ -186,7 +186,6 @@
<link rel="icon" type="image/x-icon" href="/favicon.ico" /> <link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="shortcut icon" href="/favicon.ico" /> <link rel="shortcut icon" href="/favicon.ico" />
<!-- Additional SEO meta tags -->
<meta <meta
name="robots" name="robots"
content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"
@@ -203,10 +202,8 @@
<meta name="msapplication-TileColor" content="#F7B801" /> <meta name="msapplication-TileColor" content="#F7B801" />
<meta name="msapplication-config" content="/browserconfig.xml" /> <meta name="msapplication-config" content="/browserconfig.xml" />
<!-- Canonical URL -->
<link rel="canonical" href="https://consciousnessatlas.com" /> <link rel="canonical" href="https://consciousnessatlas.com" />
<!-- Additional Open Graph tags -->
<meta property="og:site_name" content="Consciousness Atlas" /> <meta property="og:site_name" content="Consciousness Atlas" />
<meta property="og:locale" content="en_US" /> <meta property="og:locale" content="en_US" />
<meta property="og:image:width" content="1200" /> <meta property="og:image:width" content="1200" />
@@ -216,7 +213,6 @@
content="Consciousness Atlas - Interactive visualization of consciousness theories" content="Consciousness Atlas - Interactive visualization of consciousness theories"
/> />
<!-- Additional Twitter Card tags -->
<meta name="twitter:site" content="@consciousnessatlas" /> <meta name="twitter:site" content="@consciousnessatlas" />
<meta name="twitter:creator" content="@danilo_z_j" /> <meta name="twitter:creator" content="@danilo_z_j" />
<meta <meta
@@ -224,13 +220,15 @@
content="Consciousness Atlas - Interactive visualization of consciousness theories" content="Consciousness Atlas - Interactive visualization of consciousness theories"
/> />
<!-- Schema.org markup for better search visibility -->
<meta itemprop="name" content="Consciousness Atlas" /> <meta itemprop="name" content="Consciousness Atlas" />
<meta <meta
itemprop="description" itemprop="description"
content="Interactive visualization of 325+ theories from Kuhn's Landscape of Consciousness. Explore the ultimate map of the mind with 355+ theories of phenomenal consciousness in one interactive chart." content="Interactive visualization of 325+ theories from Kuhn's Landscape of Consciousness. Explore the ultimate map of the mind with 325+ theories of phenomenal consciousness in one interactive chart."
/>
<meta
itemprop="image"
content="https://consciousnessatlas.com/banner.png"
/> />
<meta itemprop="image" content="https://consciousnessatlas.com/logo.png" />
<link rel="manifest" href="/site.webmanifest" /> <link rel="manifest" href="/site.webmanifest" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
@@ -347,6 +345,10 @@
<div class="app-container"> <div class="app-container">
<div class="chart-container"> <div class="chart-container">
<div id="main"></div> <div id="main"></div>
<div class="chart-loader" id="chart-loader">
<div class="loader-spinner"></div>
<div class="loader-text">Loading chart...</div>
</div>
</div> </div>
<div class="logo-container"> <div class="logo-container">
@@ -426,8 +428,9 @@
than 325 theories of consciousness. It is based on Robert Lawrence than 325 theories of consciousness. It is based on Robert Lawrence
Kuhn's 2024 paper, Kuhn's 2024 paper,
<a <a
href="https://www.sciencedirect.com/science/article/pii/S0079610723001128" target="_blank"
rel="nofollow" href="https://doi.org/10.1016/j.pbiomolbio.2023.12.003"
rel="nofollow noopener"
>"A Landscape of Consciousness"</a >"A Landscape of Consciousness"</a
>. The Atlas maps theories that address phenomenal consciousness - the >. The Atlas maps theories that address phenomenal consciousness - the
subjective feel of experience, such as the redness of red. subjective feel of experience, such as the redness of red.
@@ -559,8 +562,9 @@
historical positions from classical thinkers. For the original historical positions from classical thinkers. For the original
academic context, see Kuhn's article on ScienceDirect: academic context, see Kuhn's article on ScienceDirect:
<a <a
href="https://www.sciencedirect.com/science/article/pii/S0079610723001128" href="https://doi.org/10.1016/j.pbiomolbio.2023.12.003"
rel="nofollow" rel="nofollow noopener"
target="_blank"
>A Landscape of Consciousness</a >A Landscape of Consciousness</a
>. >.
</p> </p>

BIN
public/banner.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 KiB

View File

@@ -3,7 +3,7 @@
"theory_title": "Integral Theory", "theory_title": "Integral Theory",
"summary": "Integral Theory is an overarching metatheory seeking to harmonize over one hundred diverse philosophical and spiritual theories into a single, coherent framework that accounts for the human condition. It posits a developmental spectrum of consciousness, charting an evolutionary course from ancient proto-consciousness to ultimate spiritual attainment.", "summary": "Integral Theory is an overarching metatheory seeking to harmonize over one hundred diverse philosophical and spiritual theories into a single, coherent framework that accounts for the human condition. It posits a developmental spectrum of consciousness, charting an evolutionary course from ancient proto-consciousness to ultimate spiritual attainment.",
"associated_thinkers": ["Ken Wilber"], "associated_thinkers": ["Ken Wilber"],
"category": "Anomalous and Altered States Theories", "category": "Anomalous and Altered States",
"subcategory": "Developmental Metatheory", "subcategory": "Developmental Metatheory",
"core_identity_tagline": "Consciousness as an Evolutionary Spectrum", "core_identity_tagline": "Consciousness as an Evolutionary Spectrum",
"classification_tags": [ "classification_tags": [

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -17,13 +17,38 @@ export class ChartContainer {
} }
init(renderer: 'canvas' | 'svg' = 'svg', theme: string = 'dark') { init(renderer: 'canvas' | 'svg' = 'svg', theme: string = 'dark') {
this.chart = echarts.init(this.container, theme, { if (this.container.clientWidth === 0 || this.container.clientHeight === 0) {
renderer console.warn('ChartContainer: Container has zero dimensions, waiting for layout...')
}) this.container.style.width = '100%'
this.container.style.height = '100%'
requestAnimationFrame(() => {
this.init(renderer, theme)
})
return
}
window.addEventListener('resize', () => { try {
this.chart?.resize() this.chart = echarts.init(this.container, theme, {
}) renderer
})
const loader = document.getElementById('chart-loader')
if (loader) {
loader.style.display = 'none'
}
window.addEventListener('resize', () => {
this.chart?.resize()
})
} catch (error) {
console.error('Failed to initialize ECharts:', error)
const loader = document.getElementById('chart-loader')
if (loader) {
loader.style.display = 'none'
}
throw error
}
} }
setOption(option: EChartsOption) { setOption(option: EChartsOption) {

View File

@@ -1,4 +1,3 @@
// Import shared mixins
@use "../styles/mixins" as *; @use "../styles/mixins" as *;
.item-details-panel { .item-details-panel {
@@ -249,7 +248,7 @@
margin-bottom: 28px; margin-bottom: 28px;
padding: 20px; padding: 20px;
background: rgba(59, 130, 246, 0.05); background: rgba(59, 130, 246, 0.05);
border-left: 3px solid rgba(59, 130, 246, 0.3); border-left: 3px solid rgba(255, 255, 255, 0.89);
border-radius: 0 8px 8px 0; border-radius: 0 8px 8px 0;
.theory-summary-text { .theory-summary-text {
@@ -441,8 +440,6 @@
} }
} }
// New styles for MTTS v5.0 sections
// Implications List Styles
.implications-list { .implications-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -452,15 +449,14 @@
.implication-item { .implication-item {
background: rgba(59, 130, 246, 0.05); background: rgba(59, 130, 246, 0.05);
border-left: 4px solid rgba(59, 130, 246, 0.4); border-left: 2px solid rgba(59, 130, 246, 0.4);
border-radius: 0 12px 12px 0; border-radius: 0 12px 12px 0;
padding: 20px; padding: 20px;
transition: all 0.3s ease; transition: all 0.3s ease;
&:hover { &:hover {
background: rgba(59, 130, 246, 0.08); background: rgba(59, 130, 246, 0.08);
transform: translateX(4px); transform: translateX(2px);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
} }
.implication-header { .implication-header {
@@ -477,7 +473,7 @@
.implication-question { .implication-question {
font-size: 16px; font-size: 16px;
font-weight: 700; font-weight: 700;
color: #649cf9; color: $primary-text;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
} }
@@ -505,7 +501,6 @@
} }
} }
// Icon-based Lists
.claims-list, .claims-list,
.sources-list, .sources-list,
.related-theories-list { .related-theories-list {
@@ -560,7 +555,6 @@
flex: 1; flex: 1;
} }
// Array list styling
.array-list { .array-list {
margin: 0.5rem 0; margin: 0.5rem 0;
padding-left: 1.5rem; padding-left: 1.5rem;
@@ -578,7 +572,6 @@
} }
} }
// Additional styles for theory sections
.theory-content { .theory-content {
.field { .field {
.field-label { .field-label {
@@ -657,7 +650,6 @@
} }
} }
// Keyframe animations
@keyframes pulse { @keyframes pulse {
0%, 0%,
100% { 100% {
@@ -703,7 +695,7 @@
.item-details-panel { .item-details-panel {
width: 100%; width: 100%;
right: -100%; right: -100%;
z-index: 9999; /* Ensure panel appears above search field on mobile */ z-index: 9999;
.panel-content { .panel-content {
padding: 20px; padding: 20px;
@@ -717,7 +709,6 @@
} }
} }
// Mobile implications adjustments
.implications-list { .implications-list {
gap: 12px; gap: 12px;
margin: 12px 0; margin: 12px 0;
@@ -751,7 +742,6 @@
} }
} }
// Mobile icon lists
.claim-item, .claim-item,
.source-item, .source-item,
.related-theory-item { .related-theory-item {
@@ -800,7 +790,6 @@
} }
} }
// Scholarly Panel Styles
.scholarly-panel { .scholarly-panel {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -811,7 +800,6 @@
color: $primary-text; color: $primary-text;
} }
// Breadcrumb
.breadcrumb { .breadcrumb {
@include outfit-font; @include outfit-font;
font-size: 12px; font-size: 12px;
@@ -827,7 +815,6 @@
} }
} }
// Headline
.headline { .headline {
@include bodoni-font; @include bodoni-font;
font-size: 42px; font-size: 42px;
@@ -838,7 +825,6 @@
margin: 0 0 16px 0; margin: 0 0 16px 0;
} }
// Thinker Line
.thinker-line { .thinker-line {
@include outfit-font; @include outfit-font;
font-size: 14px; font-size: 14px;
@@ -860,7 +846,6 @@
} }
} }
// Quote Block
blockquote { blockquote {
margin: 0; margin: 0;
padding: 0; padding: 0;
@@ -880,7 +865,6 @@ blockquote {
font-style: italic; font-style: italic;
} }
// Shields Section
.shields-section { .shields-section {
display: grid; display: grid;
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(4, 1fr);
@@ -937,7 +921,6 @@ blockquote {
} }
} }
// Callout Element - CORE ONTOLOGY Style
.callout { .callout {
border: 1px solid $accent-gold; border: 1px solid $accent-gold;
border-radius: 8px; border-radius: 8px;
@@ -1014,7 +997,6 @@ blockquote {
} }
} }
// Relations Block - CRITIQUE & RELATED THEORIES Style
.relations-block { .relations-block {
margin: 24px 0; margin: 24px 0;
@@ -1066,7 +1048,6 @@ blockquote {
} }
} }
// FAQ Section - IMPLICATIONS Style
.faq-section { .faq-section {
margin: 24px 0; margin: 24px 0;
@@ -1119,7 +1100,6 @@ blockquote {
} }
} }
// References
.references { .references {
margin-top: 32px; margin-top: 32px;
padding-top: 24px; padding-top: 24px;
@@ -1149,7 +1129,6 @@ blockquote {
} }
} }
// Bottom Action Buttons
.action-buttons { .action-buttons {
display: flex; display: flex;
gap: 12px; gap: 12px;
@@ -1185,7 +1164,6 @@ blockquote {
} }
} }
// Responsive Design
@media (max-width: 768px) { @media (max-width: 768px) {
.scholarly-panel { .scholarly-panel {
padding: 20px; padding: 20px;

View File

@@ -487,14 +487,18 @@ export class ItemDetailsPanel {
<div class="field-value">${theoryData.mechanism_and_dynamics.integration_or_binding}</div> <div class="field-value">${theoryData.mechanism_and_dynamics.integration_or_binding}</div>
</div> </div>
` : ''} ` : ''}
${theoryData.mechanism_and_dynamics.information_flow_or_representation && theoryData.mechanism_and_dynamics.information_flow_or_representation !== 'Not specified' ? `
<div class="field"> <div class="field">
<div class="field-label">Information Flow or Representation</div> <div class="field-label">Information Flow or Representation</div>
<div class="field-value">${theoryData.mechanism_and_dynamics.information_flow_or_representation}</div> <div class="field-value">${theoryData.mechanism_and_dynamics.information_flow_or_representation}</div>
</div> </div>
` : ''}
${theoryData.mechanism_and_dynamics.evolutionary_account && theoryData.mechanism_and_dynamics.evolutionary_account !== 'Not specified' ? `
<div class="field"> <div class="field">
<div class="field-label">Evolutionary Account</div> <div class="field-label">Evolutionary Account</div>
<div class="field-value">${theoryData.mechanism_and_dynamics.evolutionary_account}</div> <div class="field-value">${theoryData.mechanism_and_dynamics.evolutionary_account}</div>
</div> </div>
` : ''}
${theoryData.mechanism_and_dynamics?.core_claims_and_evidence && theoryData.mechanism_and_dynamics.core_claims_and_evidence.length > 0 ? ` ${theoryData.mechanism_and_dynamics?.core_claims_and_evidence && theoryData.mechanism_and_dynamics.core_claims_and_evidence.length > 0 ? `
<div class="field"> <div class="field">
<div class="field-label">Core Claims and Evidence</div> <div class="field-label">Core Claims and Evidence</div>
@@ -510,10 +514,12 @@ export class ItemDetailsPanel {
</div> </div>
</div> </div>
` : ''} ` : ''}
${theoryData.mechanism_and_dynamics.basis_of_belief_or_evidence_type && theoryData.mechanism_and_dynamics.basis_of_belief_or_evidence_type !== 'Not specified' ? `
<div class="field"> <div class="field">
<div class="field-label">Basis of Belief or Evidence Type</div> <div class="field-label">Basis of Belief or Evidence Type</div>
<div class="field-value">${theoryData.mechanism_and_dynamics.basis_of_belief_or_evidence_type}</div> <div class="field-value">${theoryData.mechanism_and_dynamics.basis_of_belief_or_evidence_type}</div>
</div> </div>
` : ''}
</div> </div>
</div> </div>

View File

@@ -114,7 +114,7 @@ export const applyPaletteToData = (data: any[]) => {
} else { } else {
color = '#666666' color = '#666666'
} }
const newItem = { const newItem = {
...item, ...item,
parent: parentName, parent: parentName,
@@ -124,7 +124,7 @@ export const applyPaletteToData = (data: any[]) => {
fontSize: level >= 2 || (level === 1 && parentName !== 'Materialism') ? 10 : 12 fontSize: level >= 2 || (level === 1 && parentName !== 'Materialism') ? 10 : 12
} : showLabel ? { } : showLabel ? {
fontSize: level >= 2 || (level === 1 && parentName !== 'Materialism') ? 10 : 12 fontSize: level >= 2 || (level === 1 && parentName !== 'Materialism') ? 10 : 12
} : { fontSize: 0 } } : { show: false }
} }
if (item.children) { if (item.children) {
@@ -575,5 +575,3 @@ export const getAllTheoryNames = (): string[] => {
return theoryNames return theoryNames
} }
export const chartOptions: EChartsOption = getChartOptions()

View File

@@ -20,132 +20,197 @@ globalState.initialize()
analytics.trackPageView('Home', 'landing', 'overview') analytics.trackPageView('Home', 'landing', 'overview')
const router = Router.getInstance() const router = Router.getInstance()
const theoryChart = new TheoryChart('main', router)
theoryChart.initialize()
const itemDetailsPanel = theoryChart.getItemDetailsPanel() const showLoader = () => {
const formPopup = new FormPopup('form-popup') const loader = document.getElementById('chart-loader')
if (loader) {
;(window as any).router = router loader.style.display = 'flex'
}
new SearchBar('search-container', router)
const feedbackButton = document.getElementById('feedback-button')
if (feedbackButton) {
feedbackButton.addEventListener('click', (event) => {
const rect = feedbackButton.getBoundingClientRect()
analytics.trackClick('feedback_button', {
x: event.clientX - rect.left,
y: event.clientY - rect.top
})
formPopup.show()
})
} }
const aboutButton = document.getElementById('about-button') const hideLoader = () => {
if (aboutButton) { const loader = document.getElementById('chart-loader')
aboutButton.addEventListener('click', () => { if (loader) {
window.scrollBy({ loader.style.display = 'none'
top: window.innerHeight,
behavior: 'smooth'
})
})
// Handle scroll behavior - fade out when scrolling down
let lastScrollY = window.scrollY
let ticking = false
const updateAboutButton = () => {
const currentScrollY = window.scrollY
const scrollThreshold = 100 // Start fading after 100px scroll
if (currentScrollY > scrollThreshold) {
aboutButton.classList.add('fade-out')
} else {
aboutButton.classList.remove('fade-out')
}
lastScrollY = currentScrollY
ticking = false
} }
}
const onScroll = () => { const initializeChart = () => {
if (!ticking) { const container = document.getElementById('main')
requestAnimationFrame(updateAboutButton) if (container && container.clientWidth > 0 && container.clientHeight > 0) {
ticking = true try {
const theoryChart = new TheoryChart('main', router)
theoryChart.initialize()
hideLoader()
return theoryChart
} catch (error) {
console.error('Failed to initialize chart:', error)
hideLoader()
return null
} }
} }
return null
window.addEventListener('scroll', onScroll, { passive: true })
} }
const logoContainer = document.querySelector('.logo-container') showLoader()
if (logoContainer) {
logoContainer.addEventListener('click', () => {
if ((window as any).router) {
(window as any).router.goHome()
}
})
}
itemDetailsPanel.setCloseCallback(() => router.goHome()) let theoryChart = initializeChart()
// Add click tracking for external links if (!theoryChart) {
const addLinkTracking = () => { if (document.readyState === 'loading') {
// GitHub link document.addEventListener('DOMContentLoaded', () => {
const githubLink = document.querySelector('.github-link') theoryChart = initializeChart()
if (githubLink) { if (!theoryChart) {
githubLink.addEventListener('click', (event) => { setTimeout(() => {
const rect = githubLink.getBoundingClientRect() theoryChart = initializeChart()
analytics.trackClick('github_link', { }, 100)
x: (event as MouseEvent).clientX - rect.left, }
y: (event as MouseEvent).clientY - rect.top
}, 'https://github.com')
}) })
}
// Kuhn paper links
const kuhnLinks = document.querySelectorAll('a[href*="sciencedirect.com"]')
kuhnLinks.forEach(link => {
link.addEventListener('click', (event) => {
const rect = link.getBoundingClientRect()
analytics.trackClick('kuhn_paper_link', {
x: (event as MouseEvent).clientX - rect.left,
y: (event as MouseEvent).clientY - rect.top
}, link.getAttribute('href') || '')
})
})
// Twitter/X link
const twitterLink = document.querySelector('a[href*="x.com"]')
if (twitterLink) {
twitterLink.addEventListener('click', (event) => {
const rect = twitterLink.getBoundingClientRect()
analytics.trackClick('twitter_link', {
x: (event as MouseEvent).clientX - rect.left,
y: (event as MouseEvent).clientY - rect.top
}, twitterLink.getAttribute('href') || '')
})
}
}
// Initialize link tracking after DOM is loaded
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', addLinkTracking)
} else {
addLinkTracking()
}
router.setLoadingCallback((category, theory) => {
itemDetailsPanel.showLoading(category, theory)
})
router.setTheoryChangeCallback((theory, error) => {
if (theory) {
itemDetailsPanel.showTheory(theory)
} else if (error) {
itemDetailsPanel.showError(error)
} else { } else {
itemDetailsPanel.hide() setTimeout(() => {
theoryChart = initializeChart()
}, 100)
} }
}) }
const initializeComponents = () => {
if (theoryChart) {
const itemDetailsPanel = theoryChart.getItemDetailsPanel()
const formPopup = new FormPopup('form-popup')
;(window as any).router = router
new SearchBar('search-container', router)
router.setLoadingCallback((category, theory) => {
itemDetailsPanel.showLoading(category, theory)
})
router.setTheoryChangeCallback((theory, error) => {
if (theory) {
itemDetailsPanel.showTheory(theory)
} else if (error) {
itemDetailsPanel.showError(error)
} else {
itemDetailsPanel.hide()
}
})
itemDetailsPanel.setCloseCallback(() => router.goHome())
const feedbackButton = document.getElementById('feedback-button')
if (feedbackButton) {
feedbackButton.addEventListener('click', (event) => {
const rect = feedbackButton.getBoundingClientRect()
analytics.trackClick('feedback_button', {
x: event.clientX - rect.left,
y: event.clientY - rect.top
})
formPopup.show()
})
}
const aboutButton = document.getElementById('about-button')
if (aboutButton) {
aboutButton.addEventListener('click', () => {
window.scrollBy({
top: window.innerHeight,
behavior: 'smooth'
})
})
let lastScrollY = window.scrollY
let ticking = false
const updateAboutButton = () => {
const currentScrollY = window.scrollY
const scrollThreshold = 100
if (currentScrollY > scrollThreshold) {
aboutButton.classList.add('fade-out')
} else {
aboutButton.classList.remove('fade-out')
}
lastScrollY = currentScrollY
ticking = false
}
const onScroll = () => {
if (!ticking) {
requestAnimationFrame(updateAboutButton)
ticking = true
}
}
window.addEventListener('scroll', onScroll, { passive: true })
}
const logoContainer = document.querySelector('.logo-container')
if (logoContainer) {
logoContainer.addEventListener('click', () => {
if ((window as any).router) {
(window as any).router.goHome()
}
})
}
const addLinkTracking = () => {
const githubLink = document.querySelector('.github-link')
if (githubLink) {
githubLink.addEventListener('click', (event) => {
const rect = githubLink.getBoundingClientRect()
analytics.trackClick('github_link', {
x: (event as MouseEvent).clientX - rect.left,
y: (event as MouseEvent).clientY - rect.top
}, 'https://github.com')
})
}
const kuhnLinks = document.querySelectorAll('a[href*="sciencedirect.com"]')
kuhnLinks.forEach(link => {
link.addEventListener('click', (event) => {
const rect = link.getBoundingClientRect()
analytics.trackClick('kuhn_paper_link', {
x: (event as MouseEvent).clientX - rect.left,
y: (event as MouseEvent).clientY - rect.top
}, link.getAttribute('href') || '')
})
})
const twitterLink = document.querySelector('a[href*="x.com"]')
if (twitterLink) {
twitterLink.addEventListener('click', (event) => {
const rect = twitterLink.getBoundingClientRect()
analytics.trackClick('twitter_link', {
x: (event as MouseEvent).clientX - rect.left,
y: (event as MouseEvent).clientY - rect.top
}, twitterLink.getAttribute('href') || '')
})
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', addLinkTracking)
} else {
addLinkTracking()
}
}
}
if (theoryChart) {
initializeComponents()
} else {
const checkChartReady = () => {
if (theoryChart) {
initializeComponents()
} else {
setTimeout(checkChartReady, 50)
}
}
checkChartReady()
}

View File

@@ -10,6 +10,75 @@ body {
background: #1b1b1b; background: #1b1b1b;
} }
// iPhone-style loader
.chart-loader {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1000;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.loader-spinner {
width: 40px;
height: 40px;
border: 3px solid rgba(234, 189, 97, 0.2);
border-top: 3px solid #eabd61;
border-radius: 50%;
animation: spin 1s linear infinite;
}
.loader-text {
color: #eabd61;
font-size: 14px;
font-weight: 500;
margin-top: 16px;
text-align: center;
font-family: "Outfit", sans-serif;
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
// Safari mobile fixes
@media screen and (-webkit-min-device-pixel-ratio: 0) {
.chart-container {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
// Ensure Safari calculates dimensions properly
min-width: 1px;
min-height: 1px;
}
.chart-container canvas {
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
touch-action: manipulation;
}
// Safari-specific fix for flexbox dimension calculation
.app-container {
-webkit-transform: translateZ(0);
transform: translateZ(0);
}
}
.app-container { .app-container {
display: flex; display: flex;
height: 100vh; height: 100vh;