Skip to main content

logicaffeine_web/ui/pages/
workspace.rs

1//! Subject-specific workspace page.
2//!
3//! A three-panel workspace for working with specific subjects (Logic, English,
4//! Coding, Mathematics). Layout includes:
5//!
6//! - **Sidebar**: Lesson tree with progress indicators
7//! - **Main Area**: Chat-based interaction with input area
8//! - **Inspector**: AST visualization panel
9//!
10//! # Props
11//!
12//! - `subject` - The subject to work with (logic, english, coding, math)
13//!
14//! # Route
15//!
16//! Accessed via [`Route::Workspace`](crate::ui::router::Route::Workspace).
17
18use dioxus::prelude::*;
19#[cfg(all(feature = "split", target_arch = "wasm32"))]
20use dioxus::wasm_split;
21use crate::ui::state::AppState;
22use crate::ui::components::chat::ChatDisplay;
23use crate::ui::components::input::InputArea;
24use crate::ui::components::main_nav::{MainNav, ActivePage};
25use crate::ui::seo::PageHead;
26
27const WORKSPACE_STYLE: &str = r#"
28.workspace {
29    height: 100vh;
30    display: flex;
31    flex-direction: column;
32}
33
34.workspace-header {
35    background: rgba(0, 0, 0, 0.3);
36    backdrop-filter: blur(10px);
37    padding: 16px 24px;
38    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
39    display: flex;
40    justify-content: space-between;
41    align-items: center;
42}
43
44.workspace-header .breadcrumb {
45    display: flex;
46    align-items: center;
47    gap: 8px;
48}
49
50.workspace-header .breadcrumb a {
51    color: #888;
52    text-decoration: none;
53    font-size: 14px;
54}
55
56.workspace-header .breadcrumb a:hover {
57    color: #00d4ff;
58}
59
60.workspace-header .breadcrumb span {
61    color: #666;
62}
63
64.workspace-header h1 {
65    font-size: 20px;
66    font-weight: 600;
67    background: linear-gradient(90deg, #00d4ff, #7b2cbf);
68    -webkit-background-clip: text;
69    -webkit-text-fill-color: transparent;
70}
71
72.workspace-content {
73    flex: 1;
74    display: flex;
75    overflow: hidden;
76}
77
78.sidebar {
79    width: 260px;
80    background: rgba(0, 0, 0, 0.2);
81    border-right: 1px solid rgba(255, 255, 255, 0.1);
82    padding: 20px;
83    overflow-y: auto;
84}
85
86.sidebar h3 {
87    color: #888;
88    font-size: 12px;
89    text-transform: uppercase;
90    letter-spacing: 1px;
91    margin-bottom: 16px;
92}
93
94.lesson-tree {
95    list-style: none;
96}
97
98.lesson-tree li {
99    padding: 10px 12px;
100    margin-bottom: 4px;
101    border-radius: 8px;
102    color: #aaa;
103    font-size: 14px;
104    cursor: pointer;
105    transition: all 0.2s ease;
106}
107
108.lesson-tree li:hover {
109    background: rgba(255, 255, 255, 0.05);
110    color: #fff;
111}
112
113.lesson-tree li.active {
114    background: rgba(102, 126, 234, 0.2);
115    color: #667eea;
116}
117
118.lesson-tree li.locked {
119    opacity: 0.4;
120    cursor: not-allowed;
121}
122
123.main-area {
124    flex: 1;
125    display: flex;
126    flex-direction: column;
127    overflow: hidden;
128}
129
130.inspector {
131    width: 300px;
132    background: rgba(0, 0, 0, 0.2);
133    border-left: 1px solid rgba(255, 255, 255, 0.1);
134    padding: 20px;
135    overflow-y: auto;
136}
137
138.inspector h3 {
139    color: #888;
140    font-size: 12px;
141    text-transform: uppercase;
142    letter-spacing: 1px;
143    margin-bottom: 16px;
144}
145
146.inspector-placeholder {
147    color: #666;
148    font-size: 14px;
149    font-style: italic;
150    text-align: center;
151    padding: 40px 20px;
152}
153
154@media (max-width: 900px) {
155    .sidebar, .inspector {
156        display: none;
157    }
158}
159"#;
160
161#[component(lazy)]
162pub fn Workspace(subject: String) -> Element {
163    let mut state = use_context_provider(|| Signal::new(AppState::new()));
164
165    let title = match subject.as_str() {
166        "logic" => "First-Order Logic",
167        "english" => "English",
168        "coding" => "Coding",
169        "math" => "Mathematics",
170        _ => "Workspace",
171    };
172    let page_title = format!("{} Workspace - LOGICAFFEINE", title);
173    let page_path = format!("/workspace/{}", subject);
174
175    rsx! {
176        PageHead {
177            title: page_title,
178            description: "Interactive workspace for practicing formal logic and reasoning.",
179            canonical_path: page_path,
180        }
181        style { "{WORKSPACE_STYLE}" }
182
183        MainNav { active: ActivePage::Studio, subtitle: Some(title) }
184
185        div { class: "workspace",
186            div { class: "workspace-content",
187                div { class: "sidebar",
188                    h3 { "The Path" }
189                    ul { class: "lesson-tree",
190                        li { class: "active", "1. Basic Propositions" }
191                        li { "2. Connectives" }
192                        li { "3. Quantifiers" }
193                        li { "4. Predicates" }
194                        li { class: "locked", "5. Modal Logic" }
195                        li { class: "locked", "6. Temporal Logic" }
196                    }
197
198                    h3 { style: "margin-top: 32px;", "History" }
199                    p { style: "color: #666; font-size: 13px;", "Your recent sessions will appear here." }
200                }
201
202                div { class: "main-area",
203                    ChatDisplay { messages: state.read().get_history() }
204                    InputArea { on_send: move |text| state.write().add_user_message(text) }
205                }
206
207                div { class: "inspector",
208                    h3 { "AST Inspector" }
209                    div { class: "inspector-placeholder",
210                        "Parse a sentence to see its abstract syntax tree visualization here."
211                    }
212                }
213            }
214        }
215    }
216}