4 Commits
Author SHA1 Message Date
reya 348504c33a . 2026-10-30 14:15:14 +07:00
reya 41837e487b add reveal text 2026-10-30 14:03:14 +07:00
reya 905a339e3e update ui 2026-10-30 12:51:05 +07:00
reya 6ce20927ee wip 2026-10-30 10:37:29 +07:00
2 changed files with 44 additions and 90 deletions
-2
View File
@@ -30,7 +30,6 @@ pub enum IconName {
Search,
Settings,
Settings2,
Unlock,
Upload,
Warning,
}
@@ -64,7 +63,6 @@ impl IconNamed for IconName {
Self::Search => "icons/search.svg",
Self::Settings => "icons/settings.svg",
Self::Settings2 => "icons/settings2.svg",
Self::Unlock => "icons/unlock.svg",
Self::Upload => "icons/upload.svg",
Self::Warning => "icons/warning.svg",
}
+44 -88
View File
@@ -1,18 +1,15 @@
use anyhow::Error;
use gpui::prelude::FluentBuilder;
use gpui::{
App, AppContext, Context, Div, Entity, IntoElement, ParentElement, Render, SharedString,
Styled, Subscription, Task, Window, div, px, relative,
App, AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled,
Subscription, Task, Window, div, px, relative,
};
use gpui_kit::component::button::{Button, ButtonVariants};
use gpui_kit::component::dialog::{DialogDescription, DialogFooter, DialogHeader, DialogTitle};
use gpui_kit::component::form::{field, v_form};
use gpui_kit::component::input::{Input, InputEvent, InputState};
use gpui_kit::component::{ActiveTheme, Disableable, WindowExt, v_flex};
use instant::Duration;
use nostr_connect::prelude::*;
use state::{NostrRegistry, StateEvent};
use ui::IconName;
pub fn open(window: &mut Window, cx: &mut App) {
let import = cx.new(|cx| ImportIdentity::new(window, cx));
@@ -35,6 +32,7 @@ pub fn open_unlock(window: &mut Window, cx: &mut App) {
this.close_button(false)
.overlay_closable(false)
.keyboard(false)
.title("Unlock your identity")
.child(import.clone())
});
}
@@ -76,15 +74,7 @@ impl ImportIdentity {
fn build(mode: Mode, window: &mut Window, cx: &mut Context<Self>) -> Self {
let nostr = NostrRegistry::global(cx);
let key_input = cx.new(|cx| InputState::new(window, cx).placeholder("secret or bunker://"));
let pass_input = cx.new(|cx| {
let input = InputState::new(window, cx).masked(true);
if mode == Mode::Unlock {
input.placeholder("Passphrase to unlock your identity")
} else {
input
}
});
let pass_input = cx.new(|cx| InputState::new(window, cx).masked(true));
let repass_input = cx.new(|cx| InputState::new(window, cx).masked(true));
let error = cx.new(|_| None);
@@ -245,59 +235,15 @@ impl ImportIdentity {
Ok(())
}));
}
fn render_unlock(&self, cx: &mut Context<Self>) -> Div {
v_flex()
.gap_4()
.child(
DialogHeader::new()
.child(DialogTitle::new().child("Unlock your identity"))
.child(
DialogDescription::new()
.child("Enter the passphrase used to encrypt this identity."),
),
)
.child(
v_form().child(
field()
.label("Passphrase")
.required(true)
.child(Input::new(&self.pass_input)),
),
)
.when_some(self.error.read(cx).as_ref(), |this, error| {
this.child(
div()
.text_sm()
.text_color(cx.theme().danger)
.child(error.clone()),
)
})
.child(
DialogFooter::new().child(
Button::new("unlock")
.primary()
.icon(IconName::Unlock)
.label("Unlock")
.loading(self.loading)
.disabled(self.loading)
.on_click(cx.listener(move |this, _ev, _window, cx| {
this.login(cx);
})),
),
)
}
}
impl Render for ImportIdentity {
fn render(&mut self, _window: &mut gpui::Window, cx: &mut Context<Self>) -> impl IntoElement {
if self.mode == Mode::Unlock {
return self.render_unlock(cx);
}
const BUNKER_WARN: &str = "Nostr Connect will usually take more time to get all your messages. Please keep your session open until you see all your messages.";
const KEY_WARN: &str = "Coop encrypts your key with your passphrase and stores it on this device. You only need the passphrase to sign in next time.";
let is_unlock = self.mode == Mode::Unlock;
let value = self.key_input.read(cx).value().trim().to_string();
let require_password = value.starts_with("ncryptsec1");
let require_encrypt = value.starts_with("nsec1");
@@ -311,19 +257,25 @@ impl Render for ImportIdentity {
.child(
v_flex()
.gap_2()
.child(
v_flex()
.gap_1()
.text_color(cx.theme().muted_foreground)
.child("Use secret key or bunker connection")
.child(Input::new(&self.key_input)),
)
.when(require_password, |this| {
.when(!is_unlock, |this| {
this.child(
v_flex()
.gap_1()
.text_color(cx.theme().muted_foreground)
.child("Decrypt Password:")
.child("Use secret key or bunker connection")
.child(Input::new(&self.key_input)),
)
})
.when(is_unlock || require_password, |this| {
this.child(
v_flex()
.gap_1()
.text_color(cx.theme().muted_foreground)
.child(if is_unlock {
"Passphrase to unlock your identity:"
} else {
"Decrypt Password:"
})
.child(Input::new(&self.pass_input)),
)
})
@@ -371,7 +323,7 @@ impl Render for ImportIdentity {
.child({
let content = v_flex().gap_1().child(
Button::new("login")
.label("Continue")
.label(if is_unlock { "Unlock" } else { "Continue" })
.primary()
.loading(self.loading)
.disabled(self.loading)
@@ -381,26 +333,30 @@ impl Render for ImportIdentity {
);
#[cfg(not(target_arch = "wasm32"))]
let content = content.child(
Button::new("proxy")
.label("Connect via Web Extension")
.ghost()
.disabled(self.loading)
.on_click(cx.listener(move |this, _ev, _window, cx| {
this.proxy(cx);
})),
);
let content = content.when(!is_unlock, |this| {
this.child(
Button::new("proxy")
.label("Connect via Web Extension")
.ghost()
.disabled(self.loading)
.on_click(cx.listener(move |this, _ev, _window, cx| {
this.proxy(cx);
})),
)
});
#[cfg(target_arch = "wasm32")]
let content = content.child(
Button::new("extension")
.label("Continue with Browser Extension")
.ghost()
.disabled(self.loading)
.on_click(cx.listener(move |this, _ev, _window, cx| {
this.extension(cx);
})),
);
let content = content.when(!is_unlock, |this| {
this.child(
Button::new("extension")
.label("Continue with Browser Extension")
.ghost()
.disabled(self.loading)
.on_click(cx.listener(move |this, _ev, _window, cx| {
this.extension(cx);
})),
)
});
content
})