1use dioxus::prelude::*;
26
27const BASE_URL: &str = "https://logicaffeine.com";
28const LOGO_URL: &str = "https://logicaffeine.com/assets/logo.jpeg";
29const ORG_NAME: &str = "LOGICAFFEINE";
30const GITHUB_URL: &str = "https://github.com/Brahmastra-Labs/logicaffeine";
31
32pub fn organization_schema() -> String {
34 format!(
35 r#"{{
36 "@context": "https://schema.org",
37 "@type": "Organization",
38 "name": "{ORG_NAME}",
39 "url": "{BASE_URL}",
40 "logo": "{LOGO_URL}",
41 "description": "Turn everyday English into rigorous First-Order Logic. Debug your thoughts with precision.",
42 "sameAs": ["{GITHUB_URL}", "https://x.com/logicaffeine"]
43}}"#
44 )
45}
46
47pub fn website_schema() -> String {
49 format!(
50 r#"{{
51 "@context": "https://schema.org",
52 "@type": "WebSite",
53 "name": "{ORG_NAME}",
54 "url": "{BASE_URL}",
55 "description": "Turn everyday English into rigorous First-Order Logic",
56 "potentialAction": {{
57 "@type": "SearchAction",
58 "target": "{BASE_URL}/registry?q={{search_term}}",
59 "query-input": "required name=search_term"
60 }}
61}}"#
62 )
63}
64
65pub fn software_application_schema() -> String {
67 format!(
68 r#"{{
69 "@context": "https://schema.org",
70 "@type": "SoftwareApplication",
71 "name": "LOGICAFFEINE Studio",
72 "applicationCategory": "DeveloperApplication",
73 "operatingSystem": "Web Browser",
74 "description": "Interactive playground for experimenting with First-Order Logic translations",
75 "url": "{BASE_URL}/studio",
76 "offers": {{
77 "@type": "Offer",
78 "price": "0",
79 "priceCurrency": "USD"
80 }},
81 "provider": {{
82 "@type": "Organization",
83 "name": "{ORG_NAME}",
84 "url": "{BASE_URL}"
85 }}
86}}"#
87 )
88}
89
90pub fn course_schema() -> String {
92 format!(
93 r#"{{
94 "@context": "https://schema.org",
95 "@type": "Course",
96 "name": "First-Order Logic Fundamentals",
97 "description": "Learn to translate everyday English into rigorous First-Order Logic through interactive exercises and real-world examples.",
98 "url": "{BASE_URL}/learn",
99 "provider": {{
100 "@type": "Organization",
101 "name": "{ORG_NAME}",
102 "url": "{BASE_URL}"
103 }},
104 "educationalLevel": "Beginner to Advanced",
105 "isAccessibleForFree": true,
106 "inLanguage": "en",
107 "teaches": ["First-Order Logic", "Formal Logic", "Logical Reasoning", "Symbolic Logic"]
108}}"#
109 )
110}
111
112pub fn article_schema(
114 headline: &str,
115 description: &str,
116 date_published: &str,
117 slug: &str,
118) -> String {
119 format!(
120 r#"{{
121 "@context": "https://schema.org",
122 "@type": "Article",
123 "headline": "{headline}",
124 "description": "{description}",
125 "datePublished": "{date_published}",
126 "dateModified": "{date_published}",
127 "url": "{BASE_URL}/news/{slug}",
128 "author": {{
129 "@type": "Organization",
130 "name": "{ORG_NAME}",
131 "url": "{BASE_URL}"
132 }},
133 "publisher": {{
134 "@type": "Organization",
135 "name": "{ORG_NAME}",
136 "logo": {{
137 "@type": "ImageObject",
138 "url": "{LOGO_URL}"
139 }}
140 }}
141}}"#
142 )
143}
144
145pub fn faq_schema(questions: &[(&str, &str)]) -> String {
147 let qa_items: Vec<String> = questions
148 .iter()
149 .map(|(q, a)| {
150 format!(
151 r#"{{
152 "@type": "Question",
153 "name": "{}",
154 "acceptedAnswer": {{
155 "@type": "Answer",
156 "text": "{}"
157 }}
158 }}"#,
159 q, a
160 )
161 })
162 .collect();
163
164 format!(
165 r#"{{
166 "@context": "https://schema.org",
167 "@type": "FAQPage",
168 "mainEntity": [
169 {}
170 ]
171}}"#,
172 qa_items.join(",\n ")
173 )
174}
175
176pub fn tech_article_schema(title: &str, description: &str, path: &str) -> String {
178 format!(
179 r#"{{
180 "@context": "https://schema.org",
181 "@type": "TechArticle",
182 "headline": "{title}",
183 "description": "{description}",
184 "url": "{BASE_URL}{path}",
185 "author": {{
186 "@type": "Organization",
187 "name": "{ORG_NAME}"
188 }},
189 "publisher": {{
190 "@type": "Organization",
191 "name": "{ORG_NAME}",
192 "logo": {{
193 "@type": "ImageObject",
194 "url": "{LOGO_URL}"
195 }}
196 }},
197 "proficiencyLevel": "Expert"
198}}"#
199 )
200}
201
202pub fn contact_schema() -> String {
204 format!(
205 r#"{{
206 "@context": "https://schema.org",
207 "@type": "ContactPage",
208 "name": "Contact {ORG_NAME}",
209 "description": "Get in touch about commercial licensing, partnerships, or enterprise needs. Free for individuals, universities, and teams under 25.",
210 "url": "{BASE_URL}/pricing",
211 "publisher": {{
212 "@type": "Organization",
213 "name": "{ORG_NAME}",
214 "url": "{BASE_URL}"
215 }}
216}}"#
217 )
218}
219
220pub struct BreadcrumbItem {
222 pub name: &'static str,
223 pub path: &'static str,
224}
225
226pub fn breadcrumb_schema(items: &[BreadcrumbItem]) -> String {
228 let list_items: Vec<String> = items
229 .iter()
230 .enumerate()
231 .map(|(i, item)| {
232 format!(
233 r#"{{
234 "@type": "ListItem",
235 "position": {},
236 "name": "{}",
237 "item": "{}{}"
238 }}"#,
239 i + 1,
240 item.name,
241 BASE_URL,
242 item.path
243 )
244 })
245 .collect();
246
247 format!(
248 r#"{{
249 "@context": "https://schema.org",
250 "@type": "BreadcrumbList",
251 "itemListElement": [
252 {}
253 ]
254}}"#,
255 list_items.join(",\n ")
256 )
257}
258
259pub fn roadmap_schema() -> String {
261 format!(
262 r#"{{
263 "@context": "https://schema.org",
264 "@type": "ItemList",
265 "name": "LOGICAFFEINE Development Roadmap",
266 "description": "Development milestones from English-to-Logic transpiler to universal compilation",
267 "url": "{BASE_URL}/roadmap",
268 "numberOfItems": 9,
269 "itemListElement": [
270 {{"@type": "ListItem", "position": 1, "name": "Core Transpiler", "description": "Parse English, produce First-Order Logic. 53+ linguistic phenomena."}},
271 {{"@type": "ListItem", "position": 2, "name": "Web Platform", "description": "Interactive learning, studio playground, gamification."}},
272 {{"@type": "ListItem", "position": 3, "name": "Imperative Language", "description": "Functions, structs, enums, pattern matching, standard library, I/O."}},
273 {{"@type": "ListItem", "position": 4, "name": "Type System", "description": "Refinement types, generics, type inference, sum types."}},
274 {{"@type": "ListItem", "position": 5, "name": "Concurrency & Actors", "description": "Channels, agents, structured parallelism, async/await."}},
275 {{"@type": "ListItem", "position": 6, "name": "Distributed Systems", "description": "CRDTs, P2P networking, persistent storage, conflict resolution."}},
276 {{"@type": "ListItem", "position": 7, "name": "Security & Policies", "description": "Capability-based security with policy blocks in plain English."}},
277 {{"@type": "ListItem", "position": 8, "name": "Proof Assistant", "description": "Curry-Howard in English. Trust statements, termination proofs, Z3 verification."}},
278 {{"@type": "ListItem", "position": 9, "name": "Universal Compilation", "description": "Compile to WASM. Live Codex IDE for real-time proof visualization."}}
279 ]
280}}"#
281 )
282}
283
284pub fn webpage_schema(name: &str, description: &str, path: &str) -> String {
286 format!(
287 r#"{{
288 "@context": "https://schema.org",
289 "@type": "WebPage",
290 "name": "{name}",
291 "description": "{description}",
292 "url": "{BASE_URL}{path}",
293 "isPartOf": {{
294 "@type": "WebSite",
295 "name": "{ORG_NAME}",
296 "url": "{BASE_URL}"
297 }},
298 "publisher": {{
299 "@type": "Organization",
300 "name": "{ORG_NAME}",
301 "url": "{BASE_URL}"
302 }}
303}}"#
304 )
305}
306
307pub fn profile_page_schema() -> String {
309 format!(
310 r#"{{
311 "@context": "https://schema.org",
312 "@type": "ProfilePage",
313 "name": "User Profile - {ORG_NAME}",
314 "description": "Track your logic learning progress, achievements, and streaks.",
315 "url": "{BASE_URL}/profile",
316 "isPartOf": {{
317 "@type": "WebSite",
318 "name": "{ORG_NAME}",
319 "url": "{BASE_URL}"
320 }}
321}}"#
322 )
323}
324
325pub struct PageMeta {
327 pub title: &'static str,
328 pub description: &'static str,
329 pub canonical_path: &'static str,
330 pub og_image: Option<&'static str>,
331}
332
333impl Default for PageMeta {
335 fn default() -> Self {
336 Self {
337 title: "LOGICAFFEINE | Debug Your Thoughts",
338 description: "Humanity's last programming language. Transform plain English into compiled Rust code with Z3-powered verification. Debug your thoughts with mathematical certainty.",
339 canonical_path: "/",
340 og_image: Some("/assets/OG-photo.png"),
341 }
342 }
343}
344
345pub mod pages {
347 use super::PageMeta;
348
349 pub const LANDING: PageMeta = PageMeta {
350 title: "LOGICAFFEINE | Debug Your Thoughts",
351 description: "Humanity's last programming language. Transform plain English into compiled Rust code with Z3-powered verification. Debug your thoughts with mathematical certainty.",
352 canonical_path: "/",
353 og_image: Some("/assets/OG-photo.png"),
354 };
355
356 pub const LEARN: PageMeta = PageMeta {
357 title: "Learn First-Order Logic | LOGICAFFEINE",
358 description: "Master First-Order Logic through interactive exercises. From syllogisms to modal logic, learn to reason precisely.",
359 canonical_path: "/learn",
360 og_image: Some("/assets/OG-photo.png"),
361 };
362
363 pub const STUDIO: PageMeta = PageMeta {
364 title: "Studio | LOGICAFFEINE",
365 description: "Interactive playground for experimenting with First-Order Logic translations. Try examples and see results in real-time.",
366 canonical_path: "/studio",
367 og_image: Some("/assets/OG-photo.png"),
368 };
369
370 pub const GUIDE: PageMeta = PageMeta {
371 title: "Documentation | LOGICAFFEINE",
372 description: "Comprehensive guide to LOGICAFFEINE syntax, features, and First-Order Logic concepts.",
373 canonical_path: "/guide",
374 og_image: Some("/assets/OG-photo.png"),
375 };
376
377 pub const PRICING: PageMeta = PageMeta {
378 title: "Contact | LOGICAFFEINE",
379 description: "Get in touch about commercial licensing, partnerships, or enterprise needs. Free for individuals, universities, and teams under 25.",
380 canonical_path: "/pricing",
381 og_image: Some("/assets/OG-photo.png"),
382 };
383
384 pub const CRATES: PageMeta = PageMeta {
385 title: "Crates Documentation | LOGICAFFEINE",
386 description: "Technical documentation for LOGICAFFEINE Rust crates. Integrate First-Order Logic parsing into your applications.",
387 canonical_path: "/crates",
388 og_image: Some("/assets/OG-photo.png"),
389 };
390
391 pub const ROADMAP: PageMeta = PageMeta {
392 title: "Roadmap | LOGICAFFEINE",
393 description: "See what's coming next for LOGICAFFEINE. Track our progress and upcoming features.",
394 canonical_path: "/roadmap",
395 og_image: Some("/assets/OG-photo.png"),
396 };
397
398 pub const NEWS: PageMeta = PageMeta {
399 title: "News | LOGICAFFEINE",
400 description: "Latest updates, release notes, and announcements from LOGICAFFEINE.",
401 canonical_path: "/news",
402 og_image: Some("/assets/OG-photo.png"),
403 };
404
405 pub const PRIVACY: PageMeta = PageMeta {
406 title: "Privacy Policy | LOGICAFFEINE",
407 description: "How LOGICAFFEINE collects, uses, and protects your personal information. Read our full privacy policy.",
408 canonical_path: "/privacy",
409 og_image: Some("/assets/OG-photo.png"),
410 };
411
412 pub const TERMS: PageMeta = PageMeta {
413 title: "Terms of Service | LOGICAFFEINE",
414 description: "Terms and conditions for using LOGICAFFEINE. Business Source License details and usage policies.",
415 canonical_path: "/terms",
416 og_image: Some("/assets/OG-photo.png"),
417 };
418
419 pub const PROFILE: PageMeta = PageMeta {
420 title: "Your Profile | LOGICAFFEINE",
421 description: "Track your logic learning progress, achievements, XP, and streaks on LOGICAFFEINE.",
422 canonical_path: "/profile",
423 og_image: Some("/assets/OG-photo.png"),
424 };
425
426 pub const REGISTRY: PageMeta = PageMeta {
427 title: "Package Registry | LOGICAFFEINE",
428 description: "Browse and discover community-contributed logic modules and packages for LOGICAFFEINE.",
429 canonical_path: "/registry",
430 og_image: Some("/assets/OG-photo.png"),
431 };
432
433 pub const BENCHMARKS: PageMeta = PageMeta {
434 title: "Benchmarks | LOGICAFFEINE",
435 description: "LOGOS performance benchmarks across 13 languages. Near-native speed from English source code.",
436 canonical_path: "/benchmarks",
437 og_image: Some("/assets/OG-photo.png"),
438 };
439}
440
441#[component]
450pub fn PageHead(
451 title: String,
452 description: String,
453 canonical_path: String,
454 #[props(default = String::from("/assets/OG-photo.png"))]
455 og_image: String,
456) -> Element {
457 let canonical_url = format!("{}{}", BASE_URL, canonical_path);
458 let image_url = format!("{}{}", BASE_URL, og_image);
459 let default_card = og_image == "/assets/OG-photo.png";
462
463 #[cfg(target_arch = "wasm32")]
464 {
465 update_head_meta(&title, &description, &canonical_url, &image_url);
466 }
467
468 rsx! {
469 document::Title { "{title}" }
470 if cfg!(not(target_arch = "wasm32")) {
471 document::Meta { name: "title", content: title.clone() }
472 document::Meta { name: "description", content: description.clone() }
473 document::Meta { property: "og:type", content: "website" }
474 document::Meta { property: "og:url", content: canonical_url.clone() }
475 document::Meta { property: "og:title", content: title.clone() }
476 document::Meta { property: "og:description", content: description.clone() }
477 document::Meta { property: "og:image", content: image_url.clone() }
478 if default_card {
479 document::Meta { property: "og:image:width", content: "1200" }
480 document::Meta { property: "og:image:height", content: "630" }
481 document::Meta { property: "og:image:alt", content: "LOGICAFFEINE — Debug Your Thoughts" }
482 }
483 document::Meta { name: "twitter:url", content: canonical_url.clone() }
484 document::Meta { name: "twitter:title", content: title.clone() }
485 document::Meta { name: "twitter:description", content: description.clone() }
486 document::Meta { name: "twitter:image", content: image_url.clone() }
487 document::Link { rel: "canonical", href: canonical_url.clone() }
488 }
489 }
490}
491
492#[cfg(target_arch = "wasm32")]
497fn update_head_meta(title: &str, description: &str, canonical_url: &str, image_url: &str) {
498 let Some(window) = web_sys::window() else { return };
499 let Some(doc) = window.document() else { return };
500 let Some(head) = doc.head() else { return };
501
502 let set = |selector: &str, key_attr: &str, key: &str, attr: &str, value: &str| {
503 if let Ok(Some(el)) = doc.query_selector(selector) {
504 let _ = el.set_attribute(attr, value);
505 } else if let Ok(el) = doc.create_element(if key_attr == "rel" { "link" } else { "meta" }) {
506 let _ = el.set_attribute(key_attr, key);
507 let _ = el.set_attribute(attr, value);
508 let _ = head.append_child(&el);
509 }
510 };
511 let set_name = |name: &str, value: &str| {
512 set(&format!("meta[name='{name}']"), "name", name, "content", value);
513 };
514 let set_property = |property: &str, value: &str| {
515 set(&format!("meta[property='{property}']"), "property", property, "content", value);
516 };
517
518 set_name("description", description);
520 set_name("title", title);
521 set_property("og:type", "website");
523 set_property("og:url", canonical_url);
524 set_property("og:title", title);
525 set_property("og:description", description);
526 set_property("og:image", image_url);
527 set_name("twitter:url", canonical_url);
529 set_name("twitter:title", title);
530 set_name("twitter:description", description);
531 set_name("twitter:image", image_url);
532 set("link[rel='canonical']", "rel", "canonical", "href", canonical_url);
534}
535
536#[component]
538pub fn JsonLd(schema: String) -> Element {
539 rsx! {
540 script {
541 r#type: "application/ld+json",
542 dangerous_inner_html: "{schema}"
543 }
544 }
545}
546
547#[component]
549pub fn JsonLdMultiple(schemas: Vec<String>) -> Element {
550 rsx! {
551 for schema in schemas.iter() {
552 script {
553 r#type: "application/ld+json",
554 dangerous_inner_html: "{schema}"
555 }
556 }
557 }
558}