Skip to content

Commit

Permalink
docs: eliminate use of examples symlinks
Browse files Browse the repository at this point in the history
  • Loading branch information
ccbrown committed Sep 26, 2024
1 parent 8363b67 commit 715756e
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 17 deletions.
1 change: 0 additions & 1 deletion packages/iocraft-macros/examples

This file was deleted.

75 changes: 72 additions & 3 deletions packages/iocraft-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,24 @@ impl ToTokens for ParsedComponent {
///
/// Custom components are defined by adding this macro to a function that returns an `Element`:
///
/// ```no_run
#[doc = include_str!("../examples/counter.rs")]
/// ```
/// # use iocraft::prelude::*;
/// # use std::time::Duration;
/// #[component]
/// fn Counter(mut hooks: Hooks) -> impl Into<AnyElement<'static>> {
/// let mut count = hooks.use_state(|| 0);
///
/// hooks.use_future(async move {
/// loop {
/// smol::Timer::after(Duration::from_millis(100)).await;
/// count += 1;
/// }
/// });
///
/// element! {
/// Text(color: Color::Blue, content: format!("counter: {}", count))
/// }
/// }
/// ```
///
/// The function is allowed to take up to two arguments, one named `props`, for the component's
Expand All @@ -392,7 +408,60 @@ impl ToTokens for ParsedComponent {
/// Here is an example of a component that takes a reference to a `Vec` of `User` structs via properties:
///
/// ```
#[doc = include_str!("../examples/table.rs")]
/// # use iocraft::prelude::*;
/// # struct User {
/// # id: i32,
/// # name: String,
/// # email: String,
/// # }
/// #[derive(Default, Props)]
/// struct UsersTableProps<'a> {
/// users: Option<&'a Vec<User>>,
/// }
///
/// #[component]
/// fn UsersTable<'a>(props: &UsersTableProps<'a>) -> impl Into<AnyElement<'a>> {
/// element! {
/// Box(
/// margin_top: 1,
/// margin_bottom: 1,
/// flex_direction: FlexDirection::Column,
/// width: 60,
/// border_style: BorderStyle::Round,
/// border_color: Color::Cyan,
/// ) {
/// Box(border_style: BorderStyle::Single, border_edges: Edges::Bottom, border_color: Color::Grey) {
/// Box(width: 10pct, justify_content: JustifyContent::End, padding_right: 2) {
/// Text(content: "Id", weight: Weight::Bold, decoration: TextDecoration::Underline)
/// }
///
/// Box(width: 40pct) {
/// Text(content: "Name", weight: Weight::Bold, decoration: TextDecoration::Underline)
/// }
///
/// Box(width: 50pct) {
/// Text(content: "Email", weight: Weight::Bold, decoration: TextDecoration::Underline)
/// }
/// }
///
/// #(props.users.map(|users| users.iter().enumerate().map(|(i, user)| element! {
/// Box(background_color: if i % 2 == 0 { None } else { Some(Color::DarkGrey) }) {
/// Box(width: 10pct, justify_content: JustifyContent::End, padding_right: 2) {
/// Text(content: user.id.to_string())
/// }
///
/// Box(width: 40pct) {
/// Text(content: user.name.clone())
/// }
///
/// Box(width: 50pct) {
/// Text(content: user.email.clone())
/// }
/// }
/// })).into_iter().flatten())
/// }
/// }
/// }
/// ```
#[proc_macro_attribute]
pub fn component(_attr: TokenStream, item: TokenStream) -> TokenStream {
Expand Down
1 change: 0 additions & 1 deletion packages/iocraft/examples

This file was deleted.

25 changes: 24 additions & 1 deletion packages/iocraft/src/components/context_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,30 @@ pub struct ContextProviderProps<'a> {
/// # Example
///
/// ```
#[doc = include_str!("../../examples/context.rs")]
/// # use iocraft::prelude::*;
/// struct NumberOfTheDay(i32);
///
/// #[component]
/// fn MyContextConsumer(hooks: Hooks) -> impl Into<AnyElement<'static>> {
/// let number = hooks.use_context::<NumberOfTheDay>();
///
/// element! {
/// Box(border_style: BorderStyle::Round, border_color: Color::Cyan) {
/// Text(content: "The number of the day is... ")
/// Text(color: Color::Green, weight: Weight::Bold, content: number.0.to_string())
/// Text(content: "!")
/// }
/// }
/// }
///
/// fn main() {
/// element! {
/// ContextProvider(value: Context::owned(NumberOfTheDay(42))) {
/// MyContextConsumer
/// }
/// }
/// .print();
/// }
/// ```
#[derive(Default)]
pub struct ContextProvider;
Expand Down
16 changes: 15 additions & 1 deletion packages/iocraft/src/hooks/use_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,21 @@ use std::{
/// # Example
///
/// ```
#[doc = include_str!("../../examples/context.rs")]
/// # use iocraft::prelude::*;
/// struct NumberOfTheDay(i32);
///
/// #[component]
/// fn MyContextConsumer(hooks: Hooks) -> impl Into<AnyElement<'static>> {
/// let number = hooks.use_context::<NumberOfTheDay>();
///
/// element! {
/// Box(border_style: BorderStyle::Round, border_color: Color::Cyan) {
/// Text(content: "The number of the day is... ")
/// Text(color: Color::Green, weight: Weight::Bold, content: number.0.to_string())
/// Text(content: "!")
/// }
/// }
/// }
/// ```
pub trait UseContext<'a> {
/// Returns a reference to the context of the given type.
Expand Down
20 changes: 18 additions & 2 deletions packages/iocraft/src/hooks/use_future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,24 @@ use std::{
///
/// # Example
///
/// ```no_run
#[doc = include_str!("../../examples/counter.rs")]
/// ```
/// # use iocraft::prelude::*;
/// # use std::time::Duration;
/// #[component]
/// fn Counter(mut hooks: Hooks) -> impl Into<AnyElement<'static>> {
/// let mut count = hooks.use_state(|| 0);
///
/// hooks.use_future(async move {
/// loop {
/// smol::Timer::after(Duration::from_millis(100)).await;
/// count += 1;
/// }
/// });
///
/// element! {
/// Text(color: Color::Blue, content: format!("counter: {}", count))
/// }
/// }
/// ```
pub trait UseFuture {
/// Spawns a future which is bound to the lifetime of the component. When the component is
Expand Down
23 changes: 21 additions & 2 deletions packages/iocraft/src/hooks/use_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,27 @@ use std::{
///
/// # Example
///
/// ```no_run
#[doc = include_str!("../../examples/use_output.rs")]
/// ```
/// # use iocraft::prelude::*;
/// # use std::time::Duration;
/// #[component]
/// fn Example(mut hooks: Hooks) -> impl Into<AnyElement<'static>> {
/// let (stdout, stderr) = hooks.use_output();
///
/// hooks.use_future(async move {
/// loop {
/// smol::Timer::after(Duration::from_secs(1)).await;
/// stdout.println("Hello from iocraft to stdout!");
/// stderr.println(" And hello to stderr too!");
/// }
/// });
///
/// element! {
/// Box(border_style: BorderStyle::Round, border_color: Color::Green) {
/// Text(content: "Hello, use_stdio!")
/// }
/// }
/// }
/// ```
pub trait UseOutput {
/// Gets handles which can be used to write to stdout and stderr.
Expand Down
20 changes: 18 additions & 2 deletions packages/iocraft/src/hooks/use_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,24 @@ use std::{
///
/// # Example
///
/// ```no_run
#[doc = include_str!("../../examples/counter.rs")]
/// ```
/// # use iocraft::prelude::*;
/// # use std::time::Duration;
/// #[component]
/// fn Counter(mut hooks: Hooks) -> impl Into<AnyElement<'static>> {
/// let mut count = hooks.use_state(|| 0);
///
/// hooks.use_future(async move {
/// loop {
/// smol::Timer::after(Duration::from_millis(100)).await;
/// count += 1;
/// }
/// });
///
/// element! {
/// Text(color: Color::Blue, content: format!("counter: {}", count))
/// }
/// }
/// ```
pub trait UseState {
/// Creates a new state with its initial value computed by the given function.
Expand Down
74 changes: 72 additions & 2 deletions packages/iocraft/src/hooks/use_terminal_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,78 @@ use std::{
///
/// # Example
///
/// ```no_run
#[doc = include_str!("../../examples/use_input.rs")]
/// ```
/// # use iocraft::prelude::*;
/// # use unicode_width::UnicodeWidthStr;
/// const AREA_WIDTH: u32 = 80;
/// const AREA_HEIGHT: u32 = 11;
/// const FACE: &str = "👾";
///
/// #[component]
/// fn Example(mut hooks: Hooks) -> impl Into<AnyElement<'static>> {
/// let mut system = hooks.use_context_mut::<SystemContext>();
/// let x = hooks.use_state(|| 0);
/// let y = hooks.use_state(|| 0);
/// let should_exit = hooks.use_state(|| false);
///
/// hooks.use_terminal_events({
/// move |event| match event {
/// TerminalEvent::Key(KeyEvent { code, kind, .. }) if kind != KeyEventKind::Release => {
/// match code {
/// KeyCode::Char('q') => should_exit.set(true),
/// KeyCode::Up => y.set((y.get() as i32 - 1).max(0) as _),
/// KeyCode::Down => y.set((y.get() + 1).min(AREA_HEIGHT - 1)),
/// KeyCode::Left => x.set((x.get() as i32 - 1).max(0) as _),
/// KeyCode::Right => x.set((x.get() + 1).min(AREA_WIDTH - FACE.width() as u32)),
/// _ => {}
/// }
/// }
/// _ => {}
/// }
/// });
///
/// if should_exit.get() {
/// system.exit();
/// }
///
/// element! {
/// Box(
/// flex_direction: FlexDirection::Column,
/// padding: 2,
/// align_items: AlignItems::Center
/// ) {
/// Text(content: "Use arrow keys to move. Press \"q\" to exit.")
/// Box(
/// border_style: BorderStyle::Round,
/// border_color: Color::Green,
/// height: AREA_HEIGHT + 2,
/// width: AREA_WIDTH + 2,
/// ) {
/// #(if should_exit.get() {
/// element! {
/// Box(
/// width: 100pct,
/// height: 100pct,
/// justify_content: JustifyContent::Center,
/// align_items: AlignItems::Center,
/// ) {
/// Text(content: format!("Goodbye! {}", FACE))
/// }
/// }
/// } else {
/// element! {
/// Box(
/// padding_left: x.get(),
/// padding_top: y.get(),
/// ) {
/// Text(content: FACE)
/// }
/// }
/// })
/// }
/// }
/// }
/// }
/// ```
pub trait UseTerminalEvents {
/// Defines a callback to be invoked whenever a terminal event occurs.
Expand Down
33 changes: 31 additions & 2 deletions packages/iocraft/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,19 @@
//! Here's your first `iocraft` program:
//!
//! ```
#![doc = include_str!("../examples/hello_world.rs")]
//! use iocraft::prelude::*;
//!
//! fn main() {
//! element! {
//! Box(
//! border_style: BorderStyle::Round,
//! border_color: Color::Blue,
//! ) {
//! Text(content: "Hello, world!")
//! }
//! }
//! .print();
//! }
//! ```
//!
//! Your UI is composed primarily via the [`element!`] macro, which allows you to declare your UI
Expand All @@ -36,7 +48,23 @@
//! which increments every 100ms:
//!
//! ```no_run
#![doc = include_str!("../examples/counter.rs")]
//! # use iocraft::prelude::*;
//! # use std::time::Duration;
//! #[component]
//! fn Counter(mut hooks: Hooks) -> impl Into<AnyElement<'static>> {
//! let mut count = hooks.use_state(|| 0);
//!
//! hooks.use_future(async move {
//! loop {
//! smol::Timer::after(Duration::from_millis(100)).await;
//! count += 1;
//! }
//! });
//!
//! element! {
//! Text(color: Color::Blue, content: format!("counter: {}", count))
//! }
//! }
//! ```
//!
//! ## More Examples
Expand All @@ -54,6 +82,7 @@
//! You may also want to check out [Ratatui](https://github.com/ratatui/ratatui), which serves a
//! similar purpose with a less declarative API.
#![allow(clippy::needless_doctest_main)]
#![warn(missing_docs)]

// # Organization
Expand Down

0 comments on commit 715756e

Please sign in to comment.