diff options
| author | Polesznyák Márk <contact@pml68.dev> | 2025-10-20 13:35:38 +0200 |
|---|---|---|
| committer | Polesznyák Márk <contact@pml68.dev> | 2025-10-20 13:36:22 +0200 |
| commit | 6107291a672ffc912d2cfae9ffa33dcfc7b50399 (patch) | |
| tree | a266c6d8f21490e4899fee905df1534a99068bd2 | |
| parent | ci(doc): build docs with (diff) | |
| download | iced_selection-6107291a672ffc912d2cfae9ffa33dcfc7b50399.tar.gz | |
feat: add `markdown` example
| -rw-r--r-- | .builds/ci.yml | 1 | ||||
| -rw-r--r-- | Cargo.toml | 4 | ||||
| -rw-r--r-- | examples/markdown/Cargo.toml | 13 | ||||
| -rw-r--r-- | examples/markdown/overview.md | 93 | ||||
| -rw-r--r-- | examples/markdown/src/main.rs | 74 | ||||
| -rw-r--r-- | examples/rich/src/main.rs | 2 | ||||
| -rw-r--r-- | src/markdown.rs | 7 |
7 files changed, 186 insertions, 8 deletions
diff --git a/.builds/ci.yml b/.builds/ci.yml index 689ad52..8f7aa1d 100644 --- a/.builds/ci.yml +++ b/.builds/ci.yml @@ -23,3 +23,4 @@ tasks: cd iced_selection cargo build --package name cargo build --package rich + cargo build --package markdown @@ -22,9 +22,9 @@ iced_widget.workspace = true unicode-segmentation.workspace = true [workspace.dependencies] -iced_widget = { git = "https://github.com/iced-rs/iced" } +iced_widget = { git = "https://github.com/iced-rs/iced", branch = "master" } unicode-segmentation = "1.0" -iced = { git = "https://github.com/iced-rs/iced" } +iced = { git = "https://github.com/iced-rs/iced", branch = "master" } open = "5.3" [workspace] diff --git a/examples/markdown/Cargo.toml b/examples/markdown/Cargo.toml new file mode 100644 index 0000000..ba97085 --- /dev/null +++ b/examples/markdown/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "markdown" +version = "0.0.0" +edition = "2024" + +[dependencies] +iced.workspace = true +iced.features = ["highlighter"] + +iced_selection.path = "../.." +iced_selection.features = ["markdown"] + +open.workspace = true diff --git a/examples/markdown/overview.md b/examples/markdown/overview.md new file mode 100644 index 0000000..2bb2d93 --- /dev/null +++ b/examples/markdown/overview.md @@ -0,0 +1,93 @@ +# Overview + +Inspired by [The Elm Architecture], Iced expects you to split user interfaces into four different concepts: + +* __State__ — the state of your application +* __Messages__ — user interactions or meaningful events that you care about +* __View logic__ — a way to display your __state__ as widgets that may produce __messages__ on user interaction +* __Update logic__ — a way to react to __messages__ and update your __state__ + +We can build something to see how this works! Let's say we want a simple counter that can be incremented and decremented using two buttons. + +We start by modelling the __state__ of our application: + +```rust +#[derive(Default)] +struct Counter { + value: i32, +} +``` + +Next, we need to define the possible user interactions of our counter: the button presses. These interactions are our __messages__: + +```rust +#[derive(Debug, Clone, Copy)] +pub enum Message { + Increment, + Decrement, +} +``` + +Now, let's show the actual counter by putting it all together in our __view logic__: + +```rust +use iced::widget::{button, column, text, Column}; + +impl Counter { + pub fn view(&self) -> Column<'_, Message> { + // We use a column: a simple vertical layout + column![ + // The increment button. We tell it to produce an + // `Increment` message when pressed + button("+").on_press(Message::Increment), + + // We show the value of the counter here + text(self.value).size(50), + + // The decrement button. We tell it to produce a + // `Decrement` message when pressed + button("-").on_press(Message::Decrement), + ] + } +} +``` + +Finally, we need to be able to react to any produced __messages__ and change our __state__ accordingly in our __update logic__: + +```rust +impl Counter { + // ... + + pub fn update(&mut self, message: Message) { + match message { + Message::Increment => { + self.value += 1; + } + Message::Decrement => { + self.value -= 1; + } + } + } +} +``` + +And that's everything! We just wrote a whole user interface. Let's run it: + +```rust +fn main() -> iced::Result { + iced::run("A cool counter", Counter::update, Counter::view) +} +``` + +Iced will automatically: + + 1. Take the result of our __view logic__ and layout its widgets. + 1. Process events from our system and produce __messages__ for our __update logic__. + 1. Draw the resulting user interface. + +Read the [book], the [documentation], and the [examples] to learn more! + +[book]: https://book.iced.rs/ +[documentation]: https://docs.rs/iced/ +[examples]: https://github.com/iced-rs/iced/tree/master/examples#examples +[The Elm Architecture]: https://guide.elm-lang.org/architecture/ diff --git a/examples/markdown/src/main.rs b/examples/markdown/src/main.rs new file mode 100644 index 0000000..fae13ca --- /dev/null +++ b/examples/markdown/src/main.rs @@ -0,0 +1,74 @@ +use iced::widget::{operation, row, scrollable, text_editor}; +use iced::{Element, Fill, Font, Theme, highlighter}; +use iced_selection::markdown; + +fn main() -> iced::Result { + iced::application(State::new, State::update, State::view) + .theme(Theme::CatppuccinMocha) + .run() +} + +#[derive(Default)] +struct State { + content: markdown::Content, + raw: text_editor::Content, +} + +#[derive(Debug, Clone)] +enum Message { + Edit(text_editor::Action), + LinkClicked(markdown::Url), +} + +impl State { + fn new() -> (Self, iced::Task<Message>) { + const INITIAL_CONTENT: &str = include_str!("../overview.md"); + + ( + Self { + content: markdown::Content::parse(INITIAL_CONTENT), + raw: text_editor::Content::with_text(INITIAL_CONTENT), + }, + operation::focus_next(), + ) + } + + fn update(&mut self, message: Message) { + match message { + Message::Edit(action) => { + let is_edit = action.is_edit(); + + self.raw.perform(action); + + if is_edit { + self.content = markdown::Content::parse(&self.raw.text()); + } + } + Message::LinkClicked(link) => { + let _ = open::that_in_background(link.to_string()); + } + } + } + + fn view(&self) -> Element<'_, Message> { + let editor = text_editor(&self.raw) + .placeholder("Type your Markdown here...") + .on_action(Message::Edit) + .height(Fill) + .padding(10) + .font(Font::MONOSPACE) + .highlight("markdown", highlighter::Theme::Base16Ocean); + + let preview = + markdown::view(self.content.items(), &Theme::CatppuccinMocha) + .map(Message::LinkClicked); + + row![ + editor, + scrollable(preview).spacing(10).width(Fill).height(Fill) + ] + .spacing(10) + .padding(10) + .into() + } +} diff --git a/examples/rich/src/main.rs b/examples/rich/src/main.rs index 6c47e0f..f8f7414 100644 --- a/examples/rich/src/main.rs +++ b/examples/rich/src/main.rs @@ -20,7 +20,7 @@ impl State { fn update(&mut self, message: Message) { match message { Message::LinkClicked(link) => { - let _ = open::that(&link); + let _ = open::that_in_background(&link); self.link = Some(link); } }; diff --git a/src/markdown.rs b/src/markdown.rs index a3c939a..3083d3c 100644 --- a/src/markdown.rs +++ b/src/markdown.rs @@ -1,12 +1,9 @@ //! A custom markdown viewer and its corresponding functions. -//! -//! To be used with [`view_with`] -//! -//! [`view_with`]: iced_widget::markdown::view_with use iced_widget::graphics::text::Paragraph; use iced_widget::markdown::{ - Catalog, HeadingLevel, Item, Settings, Text, Url, Viewer, view_with, + Catalog, HeadingLevel, Item, Settings, Text, Viewer, view_with, }; +pub use iced_widget::markdown::{Content, Url, parse}; use iced_widget::{column, container, row, scrollable}; use crate::core::Font; |
