wayver's git archive


an obsidian renderer
git clone https://git.wayver.dev/sable

sable-canvas/src/node/mod.rs@337ba67f65eaa17b44e371af7c0f0c761d6aa914

raw
Date Commit Message Author Files + -
2026-02-23 01:55 initial mvp wayverd 139 17808 0
...

1mod file;
2mod group;
3mod link;
4mod text;
5
6use crate::{NodeId, PixelCoordinate, PixelDimension, color::Color};
7
8pub use self::{
9    file::FileNode,
10    group::{Background, BackgroundStyle, GroupNode},
11    link::LinkNode,
12    text::TextNode,
13};
14
15/// The shared attributes all nodes have.
16#[derive(
17    Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
18)]
19pub struct GenericNode {
20    /// The unique ID of the node.
21    pub id: NodeId,
22    x: PixelCoordinate,
23    y: PixelCoordinate,
24    width: PixelDimension,
25    height: PixelDimension,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    color: Option<Color>,
28}
29
30impl GenericNode {
31    /// Creates a new [`GenericNode`].
32    #[must_use]
33    pub const fn new(
34        id: NodeId,
35        x: PixelCoordinate,
36        y: PixelCoordinate,
37        width: PixelDimension,
38        height: PixelDimension,
39        color: Option<Color>,
40    ) -> Self {
41        Self {
42            id,
43            x,
44            y,
45            width,
46            height,
47            color,
48        }
49    }
50}
51
52/// Trait to access the shared attributes of all nodes.
53pub trait GenericNodeInfo {
54    /// Get the unique ID of the node.
55    fn id(&self) -> &NodeId;
56    /// Get the `x` position of the node in pixels.
57    fn x(&self) -> PixelCoordinate;
58    /// Get the `y` position of the node in pixels.
59    fn y(&self) -> PixelCoordinate;
60    /// Get the `width` position of the node in pixels.
61    fn width(&self) -> PixelDimension;
62    /// Get the `height` position of the node in pixels.
63    fn height(&self) -> PixelDimension;
64    /// Get color of the node.
65    fn color(&self) -> &Option<Color>;
66}
67
68impl GenericNodeInfo for GenericNode {
69    fn id(&self) -> &NodeId {
70        &self.id
71    }
72
73    fn x(&self) -> PixelCoordinate {
74        self.x
75    }
76
77    fn y(&self) -> PixelCoordinate {
78        self.y
79    }
80
81    fn width(&self) -> PixelDimension {
82        self.width
83    }
84
85    fn height(&self) -> PixelDimension {
86        self.height
87    }
88
89    fn color(&self) -> &Option<Color> {
90        &self.color
91    }
92}
93
94/// Wrapper around all the types of nodes of a canvas.
95#[derive(Debug, serde::Serialize, serde::Deserialize)]
96#[serde(tag = "type", rename_all = "camelCase")]
97pub enum Node {
98    /// A text node.
99    ///
100    /// See [`TextNode`].
101    Text(TextNode),
102    /// A file node.
103    ///
104    /// See [`FileNode`].
105    File(FileNode),
106    /// A link node.
107    ///
108    /// See [`LinkNode`].
109    Link(LinkNode),
110    /// A group node.
111    ///
112    /// See [`GroupNode`].
113    Group(GroupNode),
114}
115
116impl From<GroupNode> for Node {
117    fn from(node: GroupNode) -> Self {
118        Self::Group(node)
119    }
120}
121
122impl From<TextNode> for Node {
123    fn from(node: TextNode) -> Self {
124        Self::Text(node)
125    }
126}
127
128impl From<FileNode> for Node {
129    fn from(node: FileNode) -> Self {
130        Self::File(node)
131    }
132}
133
134impl From<LinkNode> for Node {
135    fn from(node: LinkNode) -> Self {
136        Self::Link(node)
137    }
138}
139
140impl GenericNodeInfo for Node {
141    fn id(&self) -> &NodeId {
142        match &self {
143            Self::Text(node) => node.id(),
144            Self::File(node) => node.id(),
145            Self::Link(node) => node.id(),
146            Self::Group(node) => node.id(),
147        }
148    }
149
150    fn x(&self) -> PixelCoordinate {
151        match &self {
152            Self::Text(node) => node.x(),
153            Self::File(node) => node.x(),
154            Self::Link(node) => node.x(),
155            Self::Group(node) => node.x(),
156        }
157    }
158
159    fn y(&self) -> PixelCoordinate {
160        match &self {
161            Self::Text(node) => node.y(),
162            Self::File(node) => node.y(),
163            Self::Link(node) => node.y(),
164            Self::Group(node) => node.y(),
165        }
166    }
167
168    fn width(&self) -> PixelDimension {
169        match &self {
170            Self::Text(node) => node.width(),
171            Self::File(node) => node.width(),
172            Self::Link(node) => node.width(),
173            Self::Group(node) => node.width(),
174        }
175    }
176
177    fn height(&self) -> PixelDimension {
178        match &self {
179            Self::Text(node) => node.height(),
180            Self::File(node) => node.height(),
181            Self::Link(node) => node.height(),
182            Self::Group(node) => node.height(),
183        }
184    }
185
186    fn color(&self) -> &Option<Color> {
187        match &self {
188            Self::Text(node) => node.color(),
189            Self::File(node) => node.color(),
190            Self::Link(node) => node.color(),
191            Self::Group(node) => node.color(),
192        }
193    }
194}
195