I wanted a simple textarea where I could paste links and jot down quick notes. No login, no cloud sync, no fancy formatting — just a textarea that saves to localStorage. Most existing tools are overkill for this use case.
So I built ftextarea — and used it as an excuse to learn Rust + WebAssembly without frameworks.
Try the live app →
View the source code →
The Goal#
Build a static web page with:
Here’s what I’m aiming for in 2026: health and fitness, coding, learning, and writing.
This list focuses on side projects and learning goals, I’m keeping personal and work-related resolutions private.
Each goal below includes a measurable target, the bigger picture behind it, and why it matters to me.
I’ll update this post throughout the year with progress notes under each goal. Check back to see how it’s going.
Health & Fitness#
Stay in ketosis for 30 days straight#
I’ve read great things about keto for general health and weight management. I want to experience what ketosis actually feels like and figure out what it takes to get there. The 30-day target forces me to find a sustainable approach: simple recipes that work with a full-time job and a family at home.
⚠️ PLACEHOLDER CONTENT: This is a fake blog post with dummy content for demonstration purposes only.
Introduction#
Rust’s async/await syntax makes writing asynchronous code feel almost synchronous. Here’s a quick look at how it works.
Basic Example#
use tokio::time::{sleep, Duration};
async fn fetch_data(id: u32) -> String {
// Simulate network delay
sleep(Duration::from_millis(100)).await;
format!("Data for item {}", id)
}
#[tokio::main]
async fn main() {
let result = fetch_data(42).await;
println!("{}", result);
}
Spawning Concurrent Tasks#
You can run multiple futures concurrently with tokio::join!:
⚠️ PLACEHOLDER CONTENT: This is a fake blog post with dummy content for demonstration purposes only.
The Problem#
Managing state in Flutter can get messy. Here are some patterns that help.
Using ValueNotifier#
A simple approach for local state:
class CounterWidget extends StatefulWidget {
const CounterWidget({super.key});
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
final _counter = ValueNotifier<int>(0);
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<int>(
valueListenable: _counter,
builder: (context, value, child) {
return Text('Count: $value');
},
);
}
void increment() => _counter.value++;
}
Extension Methods#
Dart extension methods can clean up your code:
⚠️ PLACEHOLDER CONTENT: This is a fake blog post with dummy content for demonstration purposes only.
The ? Operator#
Rust’s ? operator makes error propagation elegant:
use std::fs::File;
use std::io::{self, Read};
fn read_config() -> io::Result<String> {
let mut file = File::open("config.toml")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
Custom Error Types#
Define your own errors with thiserror:
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("Configuration file not found")]
ConfigNotFound,
#[error("Invalid data: {0}")]
InvalidData(String),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
}
fn load_config() -> Result<Config, AppError> {
let data = std::fs::read_to_string("config.toml")
.map_err(|_| AppError::ConfigNotFound)?;
parse_config(&data)
.ok_or_else(|| AppError::InvalidData("malformed TOML".into()))
}
The anyhow Crate#
For applications (not libraries), anyhow simplifies everything: