Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// CONFIGURATION HELPERS
// CONFIGURATION HELPERS
pub fn api_base() -> &'static str {
option_env!("API_URL").unwrap_or("http://localhost:3000")
}
Expand Down
12 changes: 8 additions & 4 deletions client/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use crate::components::protected::ProtectedRoute;
use crate::pages::{
admin::AdminPage, analytics::AnalyticsPage, blogs::BlogsPage, create::CreatePage,
dashboard::DashboardPage, docs::DocsPage, embed::EmbedPage, home::LandingPage,
policy::PolicyPage, view::ViewPage,
};
use leptos::*;
use leptos_router::*;
use crate::components::protected::ProtectedRoute;
use crate::pages::{home::LandingPage, dashboard::DashboardPage, create::CreatePage, view::ViewPage, embed::EmbedPage, docs::DocsPage, blogs::BlogsPage, analytics::AnalyticsPage, admin::AdminPage, policy::PolicyPage};

#[component]
pub fn App() -> impl IntoView {
Expand All @@ -23,8 +27,8 @@ pub fn App() -> impl IntoView {
<AnalyticsPage />
</ProtectedRoute>
} />


<Route path="/new" view=move || view! {
<ProtectedRoute>
<CreatePage />
Expand Down
10 changes: 5 additions & 5 deletions client/src/components/limit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ pub fn LimitReached() -> impl IntoView {
<br/>
"Please try again later or contact the owner."
</p>

<div style="display: flex; flex-direction: column; gap: 12px; align-items: center;">
<p style="color: var(--text-main); font-size: 0.9rem; margin-bottom: 0.5rem; font-weight: 600;">
"Are you the owner?"
</p>
<a href="mailto:tryclistudio@gmail.com"
<a href="mailto:tryclistudio@gmail.com"
class="btn-secondary btn-action"
style="width: 100%; max-width: 300px; text-decoration: none; justify-content: center">
"Request More Compute"
</a>
<a href="https://ko-fi.com/V7V21TRPL5"
target="_blank"
<a href="https://ko-fi.com/V7V21TRPL5"
target="_blank"
rel="noopener noreferrer"
class="btn-secondary"
style="width: 100%; max-width: 300px; justify-content: center; color: #ffdd00; border-color: #FFDD00; font-weight: 200;">
Expand All @@ -34,4 +34,4 @@ pub fn LimitReached() -> impl IntoView {
</div>
</div>
}
}
}
9 changes: 5 additions & 4 deletions client/src/components/modal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub fn EmbedModal(
let (copied_link, set_copied_link) = create_signal(false);
let (copied_vip, set_copied_vip) = create_signal(false);
let (new_url, set_new_url) = create_signal(String::new());

let iframe_ref = create_node_ref::<leptos::html::Textarea>();
let link_ref = create_node_ref::<leptos::html::Input>();
let vip_ref = create_node_ref::<leptos::html::Input>();
Expand Down Expand Up @@ -81,7 +81,7 @@ pub fn EmbedModal(
<h3 class="modal-title" style="margin: 0; font-size: 1.25rem;">{move || title.get()}</h3>
<button class="btn-nav" on:click=move |_| on_close.call(()) style="font-size: 1.5rem; line-height: 1;">"×"</button>
</div>

// --- SECTION 1: IFRAME ---
<div style="margin-bottom: 24px; position: relative;">
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
Expand Down Expand Up @@ -134,6 +134,7 @@ pub fn EmbedModal(
view! { <span style="opacity: 0;">"Placeholder"</span> }.into_view()
}}
</div>

<div class="input-hero-wrapper" style="display: flex; gap: 0;">
<input
type="text"
Expand Down Expand Up @@ -182,7 +183,7 @@ pub fn EmbedModal(
<div class="input-hero-wrapper" style="display: flex; gap: 0;">
<input
type="text"
class="input-slug"
class="input-slug"
style="flex: 1; font-family: var(--font-mono); font-size: 0.85rem; border-top-right-radius: 0; border-bottom-right-radius: 0; padding: 10px;"
readonly
node_ref=link_ref
Expand Down Expand Up @@ -355,4 +356,4 @@ pub fn ConfirmModal(
}
}}
}
}
}
45 changes: 24 additions & 21 deletions client/src/components/protected.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
use leptos::*;
use gloo_net::http::Request;
use web_sys::RequestCredentials;
use crate::api::api_base;
use crate::types::User;
use gloo_net::http::Request;
use leptos::*;
use web_sys::RequestCredentials;

#[component]
pub fn ProtectedRoute(children: Children) -> impl IntoView {
let (user, set_user) = create_signal(None::<User>);
let (checked, set_checked) = create_signal(false);

create_resource(|| (), move |_| async move {
// FIX: Use dynamic API URL
let url = format!("{}/api/me", api_base());
let auth_req = Request::get(&url)
.credentials(RequestCredentials::Include)
.send()
.await;
create_resource(
|| (),
move |_| async move {
// FIX: Use dynamic API URL
let url = format!("{}/api/me", api_base());
let auth_req = Request::get(&url)
.credentials(RequestCredentials::Include)
.send()
.await;

match auth_req {
Ok(resp) => {
if resp.ok() {
if let Ok(u) = resp.json::<User>().await {
set_user.set(Some(u));
match auth_req {
Ok(resp) => {
if resp.ok() {
if let Ok(u) = resp.json::<User>().await {
set_user.set(Some(u));
}
}
}
Err(_) => {}
}
Err(_) => {}
}
set_checked.set(true);
});
set_checked.set(true);
},
);

let children_view = children();

Expand All @@ -49,13 +52,13 @@ pub fn ProtectedRoute(children: Children) -> impl IntoView {
<div style="display: flex; height: 100vh; justify-content: center; align-items: center; flex-direction: column; gap: 20px; background: var(--bg-dark); padding: 32px 40px;">
<h2 style="color: var(--text-main);">"Authentication Required"</h2>
<p style="color: var(--text-muted);">"Please log in to access this page"</p>
<a href=format!("{}/auth/github", api_base())
<a href=format!("{}/auth/github", api_base())
class="btn-primary btn-hero" rel="external" style="display: flex; align-items: center; gap: 10px;">
<svg height="24" width="24" viewBox="0 0 16 16" fill="currentColor" style="color: black;">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path>
</svg>
"Start Building Free"
</a>
</a>
</div>
}.into_view()
}
Expand Down
48 changes: 26 additions & 22 deletions client/src/components/terminal.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::api::ws_base;
use leptos::*;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{WebSocket, MessageEvent, ErrorEvent};
use crate::api::ws_base;
use web_sys::{ErrorEvent, MessageEvent, WebSocket};

// BINDING 1: FitAddon
// BINDING 1: FitAddon
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_name = FitAddon)]
Expand All @@ -15,7 +15,7 @@ extern "C" {
fn fit(this: &XtermFitAddon);
}

// BINDING 2: Terminal
// BINDING 2: Terminal
#[wasm_bindgen]
extern "C" {
type Terminal;
Expand All @@ -39,12 +39,12 @@ pub fn TerminalView(container_id: String) -> impl IntoView {
create_effect(move |_| {
if let Some(div) = terminal_div_ref.get() {
let term = Terminal::new();

let fit_addon = XtermFitAddon::new();
term.load_addon(&fit_addon);
term.open(&div);
fit_addon.fit();

fit_addon.fit();
let fit_addon_clone = fit_addon.clone().unchecked_into::<XtermFitAddon>();
let on_resize = Closure::<dyn FnMut()>::new(move || {
fit_addon_clone.fit();
Expand All @@ -55,49 +55,53 @@ pub fn TerminalView(container_id: String) -> impl IntoView {
window().set_onresize(None);
});
term.write(&format!("Connecting to session {}...\r\n", id_for_effect));

let term_clone: Terminal = term.clone().unchecked_into();
let ws_url = format!("{}/ws/{}", ws_base(), id_for_effect);

// FIX: Removed unwrap() on WebSocket::new
match WebSocket::new(&ws_url) {
Ok(ws) => {
let ws_cleanup = ws.clone();

on_cleanup(move || {
let _ = ws_cleanup.close();
});
let onmessage = Closure::<dyn FnMut(MessageEvent)>::new(move |e: MessageEvent| {
if let Ok(txt) = e.data().dyn_into::<js_sys::JsString>() {
term_clone.write(&String::from(txt));
}
});
let onmessage =
Closure::<dyn FnMut(MessageEvent)>::new(move |e: MessageEvent| {
if let Ok(txt) = e.data().dyn_into::<js_sys::JsString>() {
term_clone.write(&String::from(txt));
}
});
ws.set_onmessage(Some(onmessage.as_ref().unchecked_ref()));
onmessage.forget();

let ws_clone = ws.clone();
let on_data_callback = Closure::<dyn FnMut(String)>::new(move |data: String| {
let _ = ws_clone.send_with_str(&data);
});
let on_data_callback =
Closure::<dyn FnMut(String)>::new(move |data: String| {
let _ = ws_clone.send_with_str(&data);
});
term.on_data(&on_data_callback);
on_data_callback.forget();

let term_err = term.clone().unchecked_into::<Terminal>();
let onerror = Closure::<dyn FnMut(ErrorEvent)>::new(move |_| {
term_err.write("\r\n\x1b[31m[!] Connection Error.\x1b[0m\r\n");
term_err.write("\r\n\x1b[31m[!] Connection Error.\x1b[0m\r\n");
});
ws.set_onerror(Some(onerror.as_ref().unchecked_ref()));
onerror.forget();

let term_close = term.clone().unchecked_into::<Terminal>();
let onclose = Closure::<dyn FnMut()>::new(move || {
term_close.write("\r\n\x1b[33m[!] Connection Closed.\x1b[0m\r\n");
term_close.write("\r\n\x1b[33m[!] Connection Closed.\x1b[0m\r\n");
});
ws.set_onclose(Some(onclose.as_ref().unchecked_ref()));
onclose.forget();
},
}
Err(_) => {
term.write("\r\n\x1b[31m[!] Failed to initialize WebSocket connection.\x1b[0m\r\n");
term.write(
"\r\n\x1b[31m[!] Failed to initialize WebSocket connection.\x1b[0m\r\n",
);
}
}
}
Expand Down
24 changes: 12 additions & 12 deletions client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
use leptos::*;

pub mod types;
pub mod api;
pub mod app;
pub mod types;
pub mod components {
pub mod terminal;
pub mod protected;
pub mod limit;
pub mod navbar;
pub mod modal;
pub mod navbar;
pub mod protected;
pub mod terminal;
}
pub mod pages {
pub mod home;
pub mod dashboard;
pub mod admin;
pub mod analytics;
pub mod blogs;
pub mod create;
pub mod view;
pub mod embed;
pub mod dashboard;
pub mod docs;
pub mod blogs;
pub mod analytics;
pub mod admin;
pub mod embed;
pub mod home;
pub mod policy;
pub mod view;
}

pub use app::App;
Expand All @@ -29,4 +29,4 @@ pub use app::App;
pub fn main() {
console_error_panic_hook::set_once();
leptos::mount_to_body(|| view! { <App /> })
}
}
Loading