notesy::view
What a panel, a tab or a sidebar section shows is a view: plain values naming notesy's own widgets, which notesy draws. A script never draws; it describes, and a plugin's UI always looks like notesy, in any theme.
A view is a tree of parts. Each builder below returns an object
(#{ kind: "row", icon: "check", text: "Call Ana" }); set any of its other
fields after, like row.target = "call". A list is a column; plain text is
a note.
rustuse notesy::{view, Color, Icon};
fn build(note) {
let row = view::row(Icon::ArrowRight, "Record the demo video");
row.target = "video";
row.color = Color::Accent;
view::column([
view::header(Icon::Check, "Tasks", "3 left in this note"),
view::stats([["3", "to do"], ["2", "done"]]),
view::progress(2, 5),
view::caption("to do"),
row,
])
}
#Parts
| Builder | Other fields | What it is |
|---|---|---|
view::column(parts) |
parts one under another | |
view::columns(parts) |
weights, gap, min, max |
parts side by side, each as wide as its share of weights ([2, 1]: two thirds and one; equal when it has none), gap points apart (12); when there isn't room for each to be min points wide (160), as many to a row as fit, like CSS's flex-wrap. With max, the row is at most that wide, kept to the left: a toolbar in a wide tab. A part that's a list is a column in it |
view::caption(text) |
a small uppercase heading | |
view::note(text) |
color, icon |
wrapped text, faint unless it has a color |
view::header(icon, title, subtitle) |
tint |
an icon on a tinted tile, a title, a line under it |
view::fact(icon, name, value) |
a name on the left, its value on the right | |
view::stats(items) |
tiles of a big value over a label: [[value, label], …] (at most 6) |
|
view::chips(list) |
target |
chips in rows; #text ones in the tags' colors |
view::row(icon, text) |
hint, target, command, faint, color, actions |
a row, like a link in the Links panel; actions as a fold's, over its right end |
view::block(icon, title, lines) |
subtitle, target |
a soft block with lines on a bar, like a mention |
view::progress(done, total) |
color |
a bar filled to done / total |
view::button(label) |
icon, target, command, tone |
a button; tone is plain, soft, primary, danger or tag |
view::empty(icon, title, body) |
action, target |
what shows where there's nothing yet, with a button when it has an action |
view::pill(text) |
tone |
a small filled label: a state, a count; tone as a button's |
view::sparkline(values) |
unit |
a line of numbers across, from nothing at its foot to the largest at its top, which is written at the top right with its unit; at most 2,000 |
view::tiles(items) |
small tiles side by side, each #{ label, icon, value, detail, color } (color is its icon's): the hours of a forecast, say. Past the panel's edge the strip scrolls sideways; at most 48 |
|
view::fold(title, parts) |
icon, hint, color, open, actions, key |
a heading with a chevron that opens and closes what's under it, an icon (in color) before its title and a hint at its right; open unless open is false. Open or closed, it stays as the user leaves it while its view is built again, kept by its key (its title unless it has one: give two with the same title a key each). actions, up to 4 #{ icon, target, tip, lit }, are small buttons at its right while the pointer's on its line, each heard as a click on its target; a lit one shows all the time, in the accent (which of several is chosen) |
view::bars(values) |
labels, unit, max, color |
a bar a value on a scale from nothing to max (the largest, unless it says), as many of labels under them as fit, and the value under the pointer (with its label) at the top: the hours' chance of rain, say. At most 400 |
view::metrics(items) |
small cards in a grid, as many to a row as fit, each #{ label, icon, value, detail, color }: an icon and a label over a big value and a line under it. At most 48 |
|
view::range(label, low, high) |
min, max, mark, unit, icon, hint, color |
a span from low to high on a bar from min to max (the span itself unless it says): the label, a hint and an icon before it, its ends written beside it with their unit, mark a dot on the bar. A day of a forecast, say |
view::lanes(lanes) |
target, adds |
lanes of cards side by side, like a kanban board, scrolling sideways when there are more than fit: lanes is [#{ title, cards: [#{ text, detail, done }] }] (at most 12 lanes, 500 cards in one; a lane or card without its title or text keeps its place, empty). A card is dragged within its lane or into another, its box ticks it, and with adds (the hint) a field at each lane's foot adds one. Each is heard at target as an object, by places counted from 0: #{ action: "move", lane, card, to_lane, to_card } (to_card counted with it taken out), #{ action: "tick", lane, card }, #{ action: "click", lane, card } or #{ action: "add", lane, text }. Nothing moves until the script builds it again saying so |
view::markdown(text) |
markdown, drawn as notesy draws a note (headings, emphasis, code, links and tags, lists and tasks, quotes, code blocks, rules, columns), read-only; at most 20,000 characters | |
view::code(text) |
language, numbers |
code, read-only, in a well: in language's colors as a code block's fence names it (rust, py, sh, a plugin's own from [[languages]]), plain without one; its lines numbered unless numbers is false; a line wider than the well moved along with a sideways wheel (or Shift and the wheel) or a drag. At most 256 KB. Its colors come a moment after it first shows, and are kept: drawn again, it costs nothing |
view::divider() |
a thin line across | |
view::space(points) |
room, up to 64 points |
Icons, colors and tones are enums of notesy's names (Names: Icon, Color, Tone, Side, Method, Command, Zone, Event):
Icon::Check, Color::Accent, Tone::Primary. Its own icons are by
their names: the plugin's own [[icons]]
(plugin.toml), notesy's (check, clock,
file, folder, link, tag, calendar, bulb, alert, info,
arrow-right, arrow-up, pin, plugin, canvas …), or another plugin's as
<plugin id>.<name>. Colors are a theme
color's key (accent, success, warning, danger, text_muted …), one
of the plugin's own [[colors]], or #rrggbb.
#Clicks
A row, block, button or empty state with a target tells the script when
it's clicked: the panel or tab's on_click handler gets the target (and a
chip's target gets target:chip). One with a command runs that command
instead, notesy's own or a plugin's. See notesy::views.
#Inputs
Parts the user changes. Each needs a target to be heard: when it
changes, the panel or tab's on_change handler gets the target, the new
value, and the note's path (or None), and then notesy builds the view
again, so what it shows comes from the script (notesy::views).
| Builder | Other fields | What it is | What on_change gets |
|---|---|---|---|
view::switch(label, on) |
hint, icon, target |
a line with a switch at its right, like a setting | true or false |
view::check(text, done) |
target, actions |
a line with a box to tick, like a task; ticked, its text is struck through. actions as a fold's, at its right |
true or false |
view::input(hint) |
target, suggest, secret |
a field to type into; Enter sends what's in it and empties it. With suggest: true, its script suggests as it's typed in (below). With secret: true, it's masked as a password is, offers no suggestions, and no plugin hears the keys typed in it |
the text, or a suggestion's value |
view::dropdown(options, selected) |
target |
a dropdown of options, one picked | the option picked |
view::segmented(options, selected) |
target |
up to five short options side by side, one picked | the option picked |
It's dropdown and not select because select is one of Rune's own
words: a function by that name can be offered but never called.
selected is the one picked: by what it's worth, then by its name, then by
its place from 0.
options is a list. An option is its name alone, or a table when it has
more to say than that: value is what target hears when it's picked (its
name, unless it's given one of its own), subline is a second line under
its name, detail is faint text at its right, and icon is an icon before
it, notesy's or the plugin's own. An option with a subline is given a
taller row; the rest stay as they are. A segmented choice has room for
neither subline nor detail and leaves both out.
rustuse notesy::{store, view, views};
pub fn ready() {
views::panel("spans", "Spans", |note| {
let spans = [
#{ value: "day", label: "Day", subline: "Since midnight", detail: "24 hours", icon: "clock" },
#{ value: "week", label: "Week", subline: "From Monday", detail: "7 days", icon: "calendar" },
];
let span = view::dropdown(spans, store::get("span").unwrap_or("week"));
span.target = "span";
view::column([span])
});
}
Written as plain text (["Day", "Week"]), an option is its own name and its
own value, which is what every dropdown did before there was more to say.
rustuse notesy::{store, view, views};
pub fn ready() {
let tasks = views::panel("tasks", "Tasks", |note| {
let hide = view::switch("Hide done tasks", store::get("hide").unwrap_or(false));
hide.target = "hide";
let span = view::segmented(["Today", "This week"], store::get("span").unwrap_or("Today"));
span.target = "span";
view::column([hide, span])
});
tasks.on_change(|target, value, note| store::set(target, value));
}
#Suggestions
A field with suggest: true asks its script what to suggest as it's typed
in. Once typing pauses (a quarter of a second), the panel or tab's
on_suggest handler gets the target, the text and the note's path, and
answers with the view's suggest(target, text, items): then, or later,
once it knows. So what it suggests can come from anywhere it may reach:
its store, the vault, a site its manifest names (notesy::net).
Each item is text, or #{ text, detail, icon, value, view }. They show
under the field, to pick with ↑, ↓ and Enter or a click; Esc puts them
away. One with a view (any part of a view: a column of a title and a
line under it, a row with a pill) shows that instead of its icon, text and
detail, lit and picked as the rest are; what's in it is only looked at. A pick
reaches on_change with the item's value (its text, unless it has one);
Enter with none lit sends what was typed, as a field without suggestions
does. Only the answer for what was last typed shows, so one that comes back
late is left out. At most 50 show.
rustuse notesy::{json, net, store, view, views};
pub fn ready() {
let app = #{ panel: () };
app.panel = views::panel("places", "Places", |note| {
let add = view::input("Add a place");
add.target = "add";
add.suggest = true;
view::column([add])
});
app.panel.on_suggest(|target, text, note| {
net::fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${net::encode(text)}`, |result| {
let items = [];
if let Ok(response) = result {
if let Ok(answer) = json::parse(response.text) {
for r in answer.get("results").unwrap_or([]) {
items.push(#{ text: r.name, detail: r.country, icon: "pin", value: `${r.name}, ${r.country}` });
}
}
}
app.panel.suggest(target, text, items);
});
});
// What was picked (its value), or typed and sent with Enter.
app.panel.on_change(|target, value, note| store::set("place", value));
}
#Coming in
Any part can come in as it first shows: set its enter to how. notesy
plays it as its Motion setting says (with motion off, parts are simply
there): when the part first shows, as the panel opens or a new row turns
up, and again after it's been out of sight a while. Building the view
again doesn't play it again.
enter |
How it comes in |
|---|---|
"fade" |
fading in where it is |
"rise" |
fading in as it rises a little into place |
"slide" |
fading in from a little to its left |
"pop" |
fading in as it grows into place, a touch past and back |
For more say, enter is an object, #{ kind: "rise", delay: 0.2, span: 0.4, ease: "back" }: delay seconds before it starts (up to 5), over
span seconds (0.3 unless it says; up to 2), eased by name as a drawing's
keyframes are (notesy::icons). A column with a stagger
brings its parts in one after another, each that many seconds after the
one before (up to 1): a list settling in. A stagger on its own rises.
rustuse notesy::{view, Icon};
fn build(note) {
let rows = [];
for task in ["Call Ana", "Book the train", "Pack for Eryri"] {
rows.push(view::row(Icon::Check, task));
}
let head = view::header(Icon::Check, "Tasks", "3 left in this note");
head.enter = "fade";
let list = view::column(rows);
list.enter = "rise";
list.stagger = 0.04;
view::column([head, list])
}
#When something's wrong
A part that's wrong (no text on a row, a kind there isn't) shows as a red
line where it was, saying what's wrong, and the rest of the view still
shows. A view has at most 2,000 parts, nested at most 16 deep.
Every page
- Overview
- plugin.toml: Every field of plugin.toml
- Permissions: What a plugin can ask for, when notesy asks, and what changes it
- Scripts: How a script runs: its lifecycle, events, limits and errors
- Packing and installing: Making, checking, signing, packing and installing
- notesy::log: Lines for its log on the Plugins page
- notesy::events: Hearing what happens, and every event
- notesy::commands: Adding commands, and running notesy's
- notesy::store: Keeping its own data
- notesy::settings: Reading its settings
- notesy::secrets: Keys and tokens, in the system keychain
- notesy::notes: Reading and changing the vault's notes
- notesy::editor: The note in front
- notesy::templates: What templates fill in, and functions of its own for them
- notesy::files: A folder of its own
- notesy::links: Opening pages in the browser, naming links after their pages
- notesy::clipboard: Copying and pasting
- notesy::view: What panels, tabs and sections show
- notesy::sections: Sidebar sections
- notesy::hidden: Hiding notes, files and folders from the tree
- notesy::status: Status bar items
- notesy::tools: Buttons in the formatting bar
- notesy::notices: Notices
- notesy::dialogs: Asking in a dialog, notesy's kinds or its own
- notesy::wizards: Pages one after another, like a setup
- notesy::boards: Boards' cards and arrows, and kinds of card of its own
- notesy::blocks: Drawing its fenced blocks
- notesy::icons: Drawing its own icons
- notesy::net: Requests to the sites it names
- notesy::ipc: Talking to a program on this computer
- notesy::accounts: Signing in to a service
- notesy::json: Reading and writing JSON
- notesy::toml: Reading and writing TOML
- notesy::yaml: Reading and writing YAML, and a note's front matter
- notesy::time: Now, written in the user's time zone, dates read, how long ago
- notesy::math: Trigonometry and the like, for drawing
- Names: Icon, Color, Tone, Side, Method, Command, Zone, Event: Notesy's names as enums
- notesy::preview: Its own screens for notesy preview
- notesy::perf: Timing its own work
- notesy::drawings: Drawings' shapes, and buttons in their tool strip
- notesy::sound: Playing sounds, and making them as it runs
- notesy::tex: Math macros for every note's formulas
- notesy::views: Side panels, tabs of its own, and its part of the tree's hover cards
- notesy::zones: Notesy's own places — its menus, its bars and its headings