mirror of
https://github.com/danilo-znamerovszkij/c-atlas.git
synced 2025-12-23 14:08:29 -05:00
✨ add loader & preview banner
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,6 +11,7 @@ node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
/src/data/THEORY.md
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
|
||||
38
index.html
38
index.html
@@ -9,7 +9,7 @@
|
||||
</title>
|
||||
<meta
|
||||
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
|
||||
name="keywords"
|
||||
@@ -22,13 +22,13 @@
|
||||
/>
|
||||
<meta
|
||||
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:url" content="https://consciousnessatlas.com" />
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://consciousnessatlas.com/logo.png"
|
||||
content="https://consciousnessatlas.com/banner.png"
|
||||
/>
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta
|
||||
@@ -37,11 +37,11 @@
|
||||
/>
|
||||
<meta
|
||||
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
|
||||
name="twitter:image"
|
||||
content="https://consciousnessatlas.com/logo.png"
|
||||
content="https://consciousnessatlas.com/banner.png"
|
||||
/>
|
||||
|
||||
<script type="application/ld+json">
|
||||
@@ -49,7 +49,7 @@
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebApplication",
|
||||
"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",
|
||||
"applicationCategory": "EducationalApplication",
|
||||
"operatingSystem": "Web Browser",
|
||||
@@ -186,7 +186,6 @@
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<link rel="shortcut icon" href="/favicon.ico" />
|
||||
|
||||
<!-- Additional SEO meta tags -->
|
||||
<meta
|
||||
name="robots"
|
||||
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-config" content="/browserconfig.xml" />
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href="https://consciousnessatlas.com" />
|
||||
|
||||
<!-- Additional Open Graph tags -->
|
||||
<meta property="og:site_name" content="Consciousness Atlas" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
@@ -216,7 +213,6 @@
|
||||
content="Consciousness Atlas - Interactive visualization of consciousness theories"
|
||||
/>
|
||||
|
||||
<!-- Additional Twitter Card tags -->
|
||||
<meta name="twitter:site" content="@consciousnessatlas" />
|
||||
<meta name="twitter:creator" content="@danilo_z_j" />
|
||||
<meta
|
||||
@@ -224,13 +220,15 @@
|
||||
content="Consciousness Atlas - Interactive visualization of consciousness theories"
|
||||
/>
|
||||
|
||||
<!-- Schema.org markup for better search visibility -->
|
||||
<meta itemprop="name" content="Consciousness Atlas" />
|
||||
<meta
|
||||
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="preconnect" href="https://fonts.googleapis.com" />
|
||||
@@ -347,6 +345,10 @@
|
||||
<div class="app-container">
|
||||
<div class="chart-container">
|
||||
<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 class="logo-container">
|
||||
@@ -426,8 +428,9 @@
|
||||
than 325 theories of consciousness. It is based on Robert Lawrence
|
||||
Kuhn's 2024 paper,
|
||||
<a
|
||||
href="https://www.sciencedirect.com/science/article/pii/S0079610723001128"
|
||||
rel="nofollow"
|
||||
target="_blank"
|
||||
href="https://doi.org/10.1016/j.pbiomolbio.2023.12.003"
|
||||
rel="nofollow noopener"
|
||||
>"A Landscape of Consciousness"</a
|
||||
>. The Atlas maps theories that address phenomenal consciousness - the
|
||||
subjective feel of experience, such as the redness of red.
|
||||
@@ -559,8 +562,9 @@
|
||||
historical positions from classical thinkers. For the original
|
||||
academic context, see Kuhn's article on ScienceDirect:
|
||||
<a
|
||||
href="https://www.sciencedirect.com/science/article/pii/S0079610723001128"
|
||||
rel="nofollow"
|
||||
href="https://doi.org/10.1016/j.pbiomolbio.2023.12.003"
|
||||
rel="nofollow noopener"
|
||||
target="_blank"
|
||||
>A Landscape of Consciousness</a
|
||||
>.
|
||||
</p>
|
||||
|
||||
BIN
public/banner.png
Normal file
BIN
public/banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 518 KiB |
@@ -3,7 +3,7 @@
|
||||
"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.",
|
||||
"associated_thinkers": ["Ken Wilber"],
|
||||
"category": "Anomalous and Altered States Theories",
|
||||
"category": "Anomalous and Altered States",
|
||||
"subcategory": "Developmental Metatheory",
|
||||
"core_identity_tagline": "Consciousness as an Evolutionary Spectrum",
|
||||
"classification_tags": [
|
||||
|
||||
BIN
public/logo.png
BIN
public/logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 243 KiB After Width: | Height: | Size: 13 KiB |
@@ -17,13 +17,38 @@ export class ChartContainer {
|
||||
}
|
||||
|
||||
init(renderer: 'canvas' | 'svg' = 'svg', theme: string = 'dark') {
|
||||
this.chart = echarts.init(this.container, theme, {
|
||||
renderer
|
||||
})
|
||||
if (this.container.clientWidth === 0 || this.container.clientHeight === 0) {
|
||||
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', () => {
|
||||
this.chart?.resize()
|
||||
})
|
||||
try {
|
||||
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) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Import shared mixins
|
||||
@use "../styles/mixins" as *;
|
||||
|
||||
.item-details-panel {
|
||||
@@ -249,7 +248,7 @@
|
||||
margin-bottom: 28px;
|
||||
padding: 20px;
|
||||
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;
|
||||
|
||||
.theory-summary-text {
|
||||
@@ -441,8 +440,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// New styles for MTTS v5.0 sections
|
||||
// Implications List Styles
|
||||
.implications-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -452,15 +449,14 @@
|
||||
|
||||
.implication-item {
|
||||
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;
|
||||
padding: 20px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
background: rgba(59, 130, 246, 0.08);
|
||||
transform: translateX(4px);
|
||||
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
|
||||
transform: translateX(2px);
|
||||
}
|
||||
|
||||
.implication-header {
|
||||
@@ -477,7 +473,7 @@
|
||||
.implication-question {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #649cf9;
|
||||
color: $primary-text;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
@@ -505,7 +501,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Icon-based Lists
|
||||
.claims-list,
|
||||
.sources-list,
|
||||
.related-theories-list {
|
||||
@@ -560,7 +555,6 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
// Array list styling
|
||||
.array-list {
|
||||
margin: 0.5rem 0;
|
||||
padding-left: 1.5rem;
|
||||
@@ -578,7 +572,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Additional styles for theory sections
|
||||
.theory-content {
|
||||
.field {
|
||||
.field-label {
|
||||
@@ -657,7 +650,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Keyframe animations
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
100% {
|
||||
@@ -703,7 +695,7 @@
|
||||
.item-details-panel {
|
||||
width: 100%;
|
||||
right: -100%;
|
||||
z-index: 9999; /* Ensure panel appears above search field on mobile */
|
||||
z-index: 9999;
|
||||
|
||||
.panel-content {
|
||||
padding: 20px;
|
||||
@@ -717,7 +709,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile implications adjustments
|
||||
.implications-list {
|
||||
gap: 12px;
|
||||
margin: 12px 0;
|
||||
@@ -751,7 +742,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile icon lists
|
||||
.claim-item,
|
||||
.source-item,
|
||||
.related-theory-item {
|
||||
@@ -800,7 +790,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Scholarly Panel Styles
|
||||
.scholarly-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -811,7 +800,6 @@
|
||||
color: $primary-text;
|
||||
}
|
||||
|
||||
// Breadcrumb
|
||||
.breadcrumb {
|
||||
@include outfit-font;
|
||||
font-size: 12px;
|
||||
@@ -827,7 +815,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Headline
|
||||
.headline {
|
||||
@include bodoni-font;
|
||||
font-size: 42px;
|
||||
@@ -838,7 +825,6 @@
|
||||
margin: 0 0 16px 0;
|
||||
}
|
||||
|
||||
// Thinker Line
|
||||
.thinker-line {
|
||||
@include outfit-font;
|
||||
font-size: 14px;
|
||||
@@ -860,7 +846,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Quote Block
|
||||
blockquote {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -880,7 +865,6 @@ blockquote {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
// Shields Section
|
||||
.shields-section {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
@@ -937,7 +921,6 @@ blockquote {
|
||||
}
|
||||
}
|
||||
|
||||
// Callout Element - CORE ONTOLOGY Style
|
||||
.callout {
|
||||
border: 1px solid $accent-gold;
|
||||
border-radius: 8px;
|
||||
@@ -1014,7 +997,6 @@ blockquote {
|
||||
}
|
||||
}
|
||||
|
||||
// Relations Block - CRITIQUE & RELATED THEORIES Style
|
||||
.relations-block {
|
||||
margin: 24px 0;
|
||||
|
||||
@@ -1066,7 +1048,6 @@ blockquote {
|
||||
}
|
||||
}
|
||||
|
||||
// FAQ Section - IMPLICATIONS Style
|
||||
.faq-section {
|
||||
margin: 24px 0;
|
||||
|
||||
@@ -1119,7 +1100,6 @@ blockquote {
|
||||
}
|
||||
}
|
||||
|
||||
// References
|
||||
.references {
|
||||
margin-top: 32px;
|
||||
padding-top: 24px;
|
||||
@@ -1149,7 +1129,6 @@ blockquote {
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom Action Buttons
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
@@ -1185,7 +1164,6 @@ blockquote {
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive Design
|
||||
@media (max-width: 768px) {
|
||||
.scholarly-panel {
|
||||
padding: 20px;
|
||||
|
||||
@@ -487,14 +487,18 @@ export class ItemDetailsPanel {
|
||||
<div class="field-value">${theoryData.mechanism_and_dynamics.integration_or_binding}</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-label">Information Flow or Representation</div>
|
||||
<div class="field-value">${theoryData.mechanism_and_dynamics.information_flow_or_representation}</div>
|
||||
</div>
|
||||
` : ''}
|
||||
${theoryData.mechanism_and_dynamics.evolutionary_account && theoryData.mechanism_and_dynamics.evolutionary_account !== 'Not specified' ? `
|
||||
<div class="field">
|
||||
<div class="field-label">Evolutionary Account</div>
|
||||
<div class="field-value">${theoryData.mechanism_and_dynamics.evolutionary_account}</div>
|
||||
</div>
|
||||
` : ''}
|
||||
${theoryData.mechanism_and_dynamics?.core_claims_and_evidence && theoryData.mechanism_and_dynamics.core_claims_and_evidence.length > 0 ? `
|
||||
<div class="field">
|
||||
<div class="field-label">Core Claims and Evidence</div>
|
||||
@@ -510,10 +514,12 @@ export class ItemDetailsPanel {
|
||||
</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-label">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>
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ export const applyPaletteToData = (data: any[]) => {
|
||||
} else {
|
||||
color = '#666666'
|
||||
}
|
||||
|
||||
|
||||
const newItem = {
|
||||
...item,
|
||||
parent: parentName,
|
||||
@@ -124,7 +124,7 @@ export const applyPaletteToData = (data: any[]) => {
|
||||
fontSize: level >= 2 || (level === 1 && parentName !== 'Materialism') ? 10 : 12
|
||||
} : showLabel ? {
|
||||
fontSize: level >= 2 || (level === 1 && parentName !== 'Materialism') ? 10 : 12
|
||||
} : { fontSize: 0 }
|
||||
} : { show: false }
|
||||
}
|
||||
|
||||
if (item.children) {
|
||||
@@ -575,5 +575,3 @@ export const getAllTheoryNames = (): string[] => {
|
||||
return theoryNames
|
||||
}
|
||||
|
||||
export const chartOptions: EChartsOption = getChartOptions()
|
||||
|
||||
|
||||
295
src/main.ts
295
src/main.ts
@@ -20,132 +20,197 @@ globalState.initialize()
|
||||
analytics.trackPageView('Home', 'landing', 'overview')
|
||||
|
||||
const router = Router.getInstance()
|
||||
const theoryChart = new TheoryChart('main', router)
|
||||
theoryChart.initialize()
|
||||
|
||||
const itemDetailsPanel = theoryChart.getItemDetailsPanel()
|
||||
const formPopup = new FormPopup('form-popup')
|
||||
|
||||
;(window as any).router = router
|
||||
|
||||
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 showLoader = () => {
|
||||
const loader = document.getElementById('chart-loader')
|
||||
if (loader) {
|
||||
loader.style.display = 'flex'
|
||||
}
|
||||
}
|
||||
|
||||
const aboutButton = document.getElementById('about-button')
|
||||
if (aboutButton) {
|
||||
aboutButton.addEventListener('click', () => {
|
||||
window.scrollBy({
|
||||
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 hideLoader = () => {
|
||||
const loader = document.getElementById('chart-loader')
|
||||
if (loader) {
|
||||
loader.style.display = 'none'
|
||||
}
|
||||
}
|
||||
|
||||
const onScroll = () => {
|
||||
if (!ticking) {
|
||||
requestAnimationFrame(updateAboutButton)
|
||||
ticking = true
|
||||
const initializeChart = () => {
|
||||
const container = document.getElementById('main')
|
||||
if (container && container.clientWidth > 0 && container.clientHeight > 0) {
|
||||
try {
|
||||
const theoryChart = new TheoryChart('main', router)
|
||||
theoryChart.initialize()
|
||||
|
||||
hideLoader()
|
||||
|
||||
return theoryChart
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize chart:', error)
|
||||
hideLoader()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', onScroll, { passive: true })
|
||||
return null
|
||||
}
|
||||
|
||||
const logoContainer = document.querySelector('.logo-container')
|
||||
if (logoContainer) {
|
||||
logoContainer.addEventListener('click', () => {
|
||||
if ((window as any).router) {
|
||||
(window as any).router.goHome()
|
||||
}
|
||||
})
|
||||
}
|
||||
showLoader()
|
||||
|
||||
itemDetailsPanel.setCloseCallback(() => router.goHome())
|
||||
let theoryChart = initializeChart()
|
||||
|
||||
// Add click tracking for external links
|
||||
const addLinkTracking = () => {
|
||||
// GitHub link
|
||||
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')
|
||||
if (!theoryChart) {
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
theoryChart = initializeChart()
|
||||
if (!theoryChart) {
|
||||
setTimeout(() => {
|
||||
theoryChart = initializeChart()
|
||||
}, 100)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,75 @@ body {
|
||||
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 {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
|
||||
Reference in New Issue
Block a user