Compare commits
7
Commits
v0.3.2
...
47d7f9d2c3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47d7f9d2c3 | ||
|
|
12e9fcd609 | ||
|
|
72674afe05 | ||
|
|
7ba9b08d76 | ||
|
|
1a45839699 | ||
|
|
be54f54804 | ||
|
|
8212477377 |
Generated
+1
-1
@@ -2948,7 +2948,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portal"
|
name = "portal"
|
||||||
version = "0.3.2"
|
version = "0.3.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "portal"
|
name = "portal"
|
||||||
version = "0.3.2"
|
version = "0.3.5"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
|||||||
+12
-8
@@ -12,8 +12,10 @@
|
|||||||
//
|
//
|
||||||
// When a relay URL is given, the widget also speaks the redoal-relay
|
// When a relay URL is given, the widget also speaks the redoal-relay
|
||||||
// protocol (ADR-0013 in the redoal repo): announce the stroke, receive
|
// protocol (ADR-0013 in the redoal repo): announce the stroke, receive
|
||||||
// an ack carrying the stroke's gesture key + the key's own decoded
|
// an ack carrying the stroke's gesture key plus the key's own decoded
|
||||||
// path ("what the network heard", drawn as a ghost), and receive
|
// path - "what the network heard", drawn as a ghost under the stroke
|
||||||
|
// when the key is v2 or later (ADR-0014's ordered turning chain; a v1
|
||||||
|
// key's histogram decode is a blob and stays hidden) - and receive
|
||||||
// echoes of similar strokes other visitors drew, shown as thumbnails.
|
// echoes of similar strokes other visitors drew, shown as thumbnails.
|
||||||
// Everything network is best-effort: no relay, refused connection, or
|
// Everything network is best-effort: no relay, refused connection, or
|
||||||
// a dropped socket all degrade to a plain offline drawing input.
|
// a dropped socket all degrade to a plain offline drawing input.
|
||||||
@@ -26,13 +28,13 @@
|
|||||||
const THEMES = {
|
const THEMES = {
|
||||||
dark: {
|
dark: {
|
||||||
stroke: '#8ec2c0',
|
stroke: '#8ec2c0',
|
||||||
ghost: 'rgba(255, 255, 255, 0.28)',
|
|
||||||
echo: '#8ec2c0',
|
echo: '#8ec2c0',
|
||||||
|
ghost: 'rgba(255, 255, 255, 0.28)',
|
||||||
},
|
},
|
||||||
light: {
|
light: {
|
||||||
stroke: '#47807e',
|
stroke: '#47807e',
|
||||||
ghost: 'rgba(29, 29, 27, 0.30)',
|
|
||||||
echo: '#47807e',
|
echo: '#47807e',
|
||||||
|
ghost: 'rgba(29, 29, 27, 0.30)',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,8 +48,8 @@ class GestureWidget {
|
|||||||
this.container = container;
|
this.container = container;
|
||||||
this.hidden = hidden || null;
|
this.hidden = hidden || null;
|
||||||
this.relayUrl = relayUrl || '';
|
this.relayUrl = relayUrl || '';
|
||||||
this.points = [];
|
|
||||||
this.ghost = null;
|
this.ghost = null;
|
||||||
|
this.points = [];
|
||||||
this.drawing = false;
|
this.drawing = false;
|
||||||
this.stopped = false;
|
this.stopped = false;
|
||||||
this.ws = null;
|
this.ws = null;
|
||||||
@@ -111,10 +113,10 @@ class GestureWidget {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.canvas.setPointerCapture(e.pointerId);
|
this.canvas.setPointerCapture(e.pointerId);
|
||||||
// One stroke only - a new pointerdown replaces the old drawing
|
// One stroke only - a new pointerdown replaces the old drawing
|
||||||
// (and any ghost/ambient trails from the previous round).
|
// (and any ghost from the previous round).
|
||||||
this.drawing = true;
|
this.drawing = true;
|
||||||
this.points = [this.pos(e)];
|
|
||||||
this.ghost = null;
|
this.ghost = null;
|
||||||
|
this.points = [this.pos(e)];
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +217,9 @@ class GestureWidget {
|
|||||||
if (this.points.length >= 2) {
|
if (this.points.length >= 2) {
|
||||||
this.setValue({ points: this.normalized(), key: msg.key });
|
this.setValue({ points: this.normalized(), key: msg.key });
|
||||||
}
|
}
|
||||||
this.ghost = msg.path;
|
// Version nibble is the key's first hex digit.
|
||||||
|
const version = parseInt((msg.key || '0')[0], 16);
|
||||||
|
this.ghost = version >= 2 && Array.isArray(msg.path) ? msg.path : null;
|
||||||
this.render();
|
this.render();
|
||||||
} else if (msg.type === 'echo') {
|
} else if (msg.type === 'echo') {
|
||||||
this.addEchoThumbnail(msg);
|
this.addEchoThumbnail(msg);
|
||||||
|
|||||||
+20
-4
@@ -1177,7 +1177,17 @@ fn AlternativeCard(
|
|||||||
children=move |e| view! { <p class="alt-encouragement">{e}</p> }
|
children=move |e| view! { <p class="alt-encouragement">{e}</p> }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{if is_gateway {
|
{if alternative.disabled {
|
||||||
|
// Advertised, not yet takeable: the label
|
||||||
|
// stays (it says what will be possible),
|
||||||
|
// the button doesn't act.
|
||||||
|
view! {
|
||||||
|
<button type="button" class="alt-submit soon" disabled=true title="Not yet">
|
||||||
|
{button_label.clone()}
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
.into_any()
|
||||||
|
} else if is_gateway {
|
||||||
let href = alternative.action.clone().unwrap_or_default();
|
let href = alternative.action.clone().unwrap_or_default();
|
||||||
view! {
|
view! {
|
||||||
<a class="alt-submit" href=href>{button_label.clone()}</a>
|
<a class="alt-submit" href=href>{button_label.clone()}</a>
|
||||||
@@ -1300,6 +1310,12 @@ fn ResourceValue(
|
|||||||
return view! { <p class="resource-empty">{empty}</p> }.into_any();
|
return view! { <p class="resource-empty">{empty}</p> }.into_any();
|
||||||
}
|
}
|
||||||
if let serde_json::Value::Array(items) = &value {
|
if let serde_json::Value::Array(items) = &value {
|
||||||
|
// Before the Answer parse below: an empty list deserializes as
|
||||||
|
// an (empty) Vec<Answer> too, and rendered as a blank
|
||||||
|
// answer-list instead of saying anything.
|
||||||
|
if items.is_empty() {
|
||||||
|
return view! { <p class="resource-empty">{empty}</p> }.into_any();
|
||||||
|
}
|
||||||
if let Ok(answers) = serde_json::from_value::<Vec<Answer>>(value.clone()) {
|
if let Ok(answers) = serde_json::from_value::<Vec<Answer>>(value.clone()) {
|
||||||
let mut answers = answers;
|
let mut answers = answers;
|
||||||
answers.sort_by(|a, b| {
|
answers.sort_by(|a, b| {
|
||||||
@@ -1332,9 +1348,6 @@ fn ResourceValue(
|
|||||||
}
|
}
|
||||||
.into_any();
|
.into_any();
|
||||||
}
|
}
|
||||||
if items.is_empty() {
|
|
||||||
return view! { <p class="resource-empty">{empty}</p> }.into_any();
|
|
||||||
}
|
|
||||||
// A list of plain objects (e.g. a jq-shaped GiteaStarred/Url
|
// A list of plain objects (e.g. a jq-shaped GiteaStarred/Url
|
||||||
// resource) - render as cards rather than dumping raw JSON.
|
// resource) - render as cards rather than dumping raw JSON.
|
||||||
// Generic on purpose, no content-declared "kind": `name`/`title`
|
// Generic on purpose, no content-declared "kind": `name`/`title`
|
||||||
@@ -1857,6 +1870,9 @@ pub async fn submit_answer(
|
|||||||
.iter()
|
.iter()
|
||||||
.find(|a| a.name == alternative)
|
.find(|a| a.name == alternative)
|
||||||
.ok_or_else(|| ServerFnError::new("unknown alternative"))?;
|
.ok_or_else(|| ServerFnError::new("unknown alternative"))?;
|
||||||
|
if alt.disabled {
|
||||||
|
return Err(ServerFnError::new("this alternative isn't open yet"));
|
||||||
|
}
|
||||||
let next = alt.action.clone();
|
let next = alt.action.clone();
|
||||||
let record_as = alt.record_as.clone();
|
let record_as = alt.record_as.clone();
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,11 @@ pub struct Alternative {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub action: Option<String>,
|
pub action: Option<String>,
|
||||||
|
/// Shown but not takeable yet - the button renders disabled and the
|
||||||
|
/// server refuses the submission. For advertising a path before it
|
||||||
|
/// works (lysbue had the same flag).
|
||||||
|
#[serde(default)]
|
||||||
|
pub disabled: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub consequence: Vec<String>,
|
pub consequence: Vec<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|||||||
@@ -675,6 +675,13 @@ textarea:focus {
|
|||||||
cursor: wait;
|
cursor: wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A content-disabled alternative (`disabled: true`): announced, not
|
||||||
|
yet takeable - reads as a promise, not as a stuck form. */
|
||||||
|
.alt-submit.soon:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
.gate-card {
|
.gate-card {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user