3 Commits
0.1.0 ... 0.1.1

Author SHA1 Message Date
01e9fb4256 Add https:// scheme if url is scheme-less 2024-02-10 18:38:38 +01:00
f74ebb45e1 Add setup page in case base_url is empty 2024-02-10 17:03:46 +01:00
13a2e52f9d Fix quote style in JS 2024-02-10 16:29:31 +01:00
5 changed files with 97 additions and 25 deletions

56
html/index.html Normal file
View File

@@ -0,0 +1,56 @@
<html>
<head>
<title>SilverBullet</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
* {
box-sizing: border-box;
}
main {
display: flex;
margin: 0 auto;
align-items: center;
justify-content: center;
min-height: 100vh;
max-width: 768px;
}
input, button {
padding: 10px;
margin: 5px 0;
width: 100%;
}
</style>
</head>
<body>
<main>
<form id="set_url" target="#">
<label for="url"><b>Set your SilverBullet instance</b></label>
<input type="url" id="url" name="url" required autofocus />
<button type="submit">Submit</button>
</form>
</main>
<script>
const form = document.getElementById('set_url');
form.addEventListener('submit', async (e) => {
try {
// Test that the URL is a valid URL.
const url = new URL(form.elements['url'].value);
// Test that the URL resolves to an actual website.
await fetch(url.href, { method: 'HEAD', mode: 'no-cors' });
window.ipc.postMessage(JSON.stringify({ command: 'set_url', url }));
window.location.assign(url);
} catch(e) {
if (e instanceof TypeError) {
// Fetch failed due to network error (dns, etc.)
alert('Failed to connect to SilverBullet due to a network error.\nPlease check that the URL is correct and you are connected.');
} else {
alert('The SilverBullet URL doesn\'t seem to be valid.\nPlease check that the URL is correct.');
}
}
e.preventDefault();
});
</script>
</body>
</html>

View File

@@ -11,7 +11,7 @@ window.addEventListener('load', () => {
if (target.href !== null) {
if (target.host !== window.location.host) {
window.ipc.postMessage(JSON.stringify({
command: "open",
command: 'open',
uri: target.href,
}));
e.preventDefault();

View File

@@ -1,4 +1,4 @@
use eyre::eyre;
use confy::ConfyError;
use serde::{Deserialize, Serialize};
pub const APP_NAME: &str = env!("CARGO_PKG_NAME");
@@ -10,11 +10,11 @@ pub struct Config {
}
impl Config {
pub fn load() -> eyre::Result<Self> {
let cfg: Config = confy::load(APP_NAME, "config")?;
if cfg.base_url.is_empty() {
return Err(eyre!("base_url must not be empty"));
}
Ok(cfg)
pub fn load() -> Result<Self, ConfyError> {
confy::load(APP_NAME, "config")
}
pub fn store(&self) -> Result<(), ConfyError> {
confy::store(APP_NAME, "config", self)
}
}

View File

@@ -2,10 +2,13 @@ use std::process;
use serde::{Deserialize, Serialize};
use crate::config::Config;
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "command", rename_all = "lowercase")]
#[serde(tag = "command", rename_all = "snake_case")]
pub enum Command {
Open { uri: String },
SetUrl { url: String },
}
impl Command {
@@ -15,6 +18,12 @@ impl Command {
process::Command::new("xdg-open").arg(uri).output()?;
Ok(())
}
Command::SetUrl { url } => {
let cfg = Config {
base_url: url.to_string(),
};
Ok(cfg.store()?)
}
}
}
}

View File

@@ -15,27 +15,34 @@ pub fn run(cfg: Config) -> eyre::Result<()> {
.with_title("SilverBullet")
.build(&event_loop)?;
let builder = WebViewBuilder::new_gtk(
window
.default_vbox()
.ok_or_else(|| eyre!("failed to get vbox"))?,
);
let data_dir = dirs::state_dir()
.ok_or_else(|| eyre!("failed to find state dir"))?
.join(APP_NAME);
let mut context = WebContext::new(Some(data_dir));
let webview = builder
.with_initialization_script(include_str!("../js/init.js"))
.with_ipc_handler(|msg| match serde_json::from_str::<Command>(&msg) {
Ok(cmd) => cmd
.handle()
.unwrap_or_else(|err| eprintln!("failed to handle command: {err}")),
Err(err) => eprintln!("invalid ipc command {msg}: {err}"),
})
.with_web_context(&mut context)
.with_url(&cfg.base_url)?
.build()?;
let mut builder = WebViewBuilder::new_gtk(
window
.default_vbox()
.ok_or_else(|| eyre!("failed to get vbox"))?,
)
.with_initialization_script(include_str!("../js/init.js"))
.with_ipc_handler(|msg| match serde_json::from_str::<Command>(&msg) {
Ok(cmd) => cmd
.handle()
.unwrap_or_else(|err| eprintln!("failed to handle command: {err}")),
Err(err) => eprintln!("invalid ipc command {msg}: {err}"),
})
.with_web_context(&mut context);
if cfg.base_url.is_empty() {
builder = builder.with_html(include_str!("../html/index.html"))?;
} else {
let mut base_url = cfg.base_url;
if !(base_url.starts_with("http://") || base_url.starts_with("https://")) {
base_url.insert_str(0, "https://");
}
builder = builder.with_url(&base_url)?;
}
let webview = builder.build()?;
let mut modifiers = ModifiersState::default();
event_loop.run(move |event, _, control_flow| {