https://github.com/heitorgandolfi/ipe-elm
A beautiful, type-safe storage library for Elm applications. Simple, elegant, and powerful.
https://github.com/heitorgandolfi/ipe-elm
elm elm-lang elm-ports javascript-interop localstorage sessionstorage
Last synced: 15 days ago
JSON representation
A beautiful, type-safe storage library for Elm applications. Simple, elegant, and powerful.
- Host: GitHub
- URL: https://github.com/heitorgandolfi/ipe-elm
- Owner: heitorgandolfi
- License: bsd-3-clause
- Created: 2025-07-04T15:25:30.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2025-07-04T16:44:54.000Z (10 months ago)
- Last Synced: 2025-07-04T16:47:35.018Z (10 months ago)
- Topics: elm, elm-lang, elm-ports, javascript-interop, localstorage, sessionstorage
- Language: JavaScript
- Homepage:
- Size: 43 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Ipê - Elegant Storage for Elm 🌸
[](https://package.elm-lang.org/)
[](https://github.com/heitorgandolfi/ipe-elm/releases)
> A beautiful, type-safe storage library for Elm applications. Simple, elegant, and powerful.
## About Ipê
Just like the Ipê tree that blooms magnificently, this library aims to make your Elm applications flourish with elegant and reliable storage capabilities.
## Features
- **Type-safe** - Full Elm type safety for your storage operations
- **Universal** - Works with both LocalStorage and SessionStorage
- **Simple API** - Clean, intuitive interface
- **Zero dependencies** - Lightweight and focused
- **Modern** - Built for Elm 0.19.1+
- **Reactive** - Subscription-based data updates
- **Error handling** - Comprehensive error management
## Installation
```bash
elm install heitorgandolfi/ipe-elm
```
## Quick Start
### 1. Add the required ports to your Elm module
```elm
port module Main exposing (..)
import Ipe exposing (StorageType(..), Error(..))
import Json.Encode as Encode
import Json.Decode as Decode
-- Required ports
port saveToStorage : Encode.Value -> Cmd msg
port loadFromStorage : Encode.Value -> Cmd msg
port removeFromStorage : Encode.Value -> Cmd msg
port receiveStorageResult : (Encode.Value -> msg) -> Sub msg
-- Helper functions to connect Ipê with your ports
saveToIpe : StorageType -> String -> Encode.Value -> Cmd msg
saveToIpe storageType key value =
Ipe.save storageType key value |> saveToStorage
loadFromIpe : StorageType -> String -> Cmd msg
loadFromIpe storageType key =
Ipe.load storageType key |> loadFromStorage
removeFromIpe : StorageType -> String -> Cmd msg
removeFromIpe storageType key =
Ipe.remove storageType key |> removeFromStorage
```
### 2. Set up the JavaScript bridge
Copy this code to your JavaScript file and call `setupIpePorts(app)` after initializing your Elm app:
```javascript
function setupIpePorts(app) {
app.ports.saveToStorage.subscribe((payload) => {
try {
const { storageType, key, value } = payload;
const data = JSON.stringify(value);
if (storageType === "local") {
localStorage.setItem(key, data);
} else {
sessionStorage.setItem(key, data);
}
} catch (e) {
console.error("Ipê (save): Failed to save to storage.", e);
}
});
app.ports.loadFromStorage.subscribe((payload) => {
try {
const { storageType, key } = payload;
let data = null;
if (storageType === "local") {
data = localStorage.getItem(key);
} else {
data = sessionStorage.getItem(key);
}
let parsed = null;
if (data !== null) {
try {
parsed = JSON.parse(data);
} catch (parseError) {
parsed = data;
}
}
app.ports.receiveStorageResult.send({ key, data: parsed });
} catch (e) {
console.error("Ipê (load): Failed to load from storage.", e);
}
});
app.ports.removeFromStorage.subscribe((payload) => {
try {
const { storageType, key } = payload;
if (storageType === "local") {
localStorage.removeItem(key);
} else {
sessionStorage.removeItem(key);
}
} catch (e) {
console.error("Ipê (remove): Failed to remove from storage.", e);
}
});
}
// Initialize your Elm app and connect the ports
var app = Elm.Main.init({ node: document.getElementById('app') });
setupIpePorts(app);
```
### 3. Use Ipê in your Elm code
```elm
type Msg
= SaveUser
| LoadUser
| StorageReceived Encode.Value
type alias User = { name : String, email : String }
-- Save data
saveUser : User -> Cmd Msg
saveUser user =
saveToIpe Local "current-user" (encodeUser user)
-- Load data
loadUser : Cmd Msg
loadUser =
loadFromIpe Local "current-user"
-- Remove data
removeUser : Cmd Msg
removeUser =
removeFromIpe Local "current-user"
-- Subscribe to storage events
subscriptions : Model -> Sub Msg
subscriptions _ =
receiveStorageResult StorageReceived
-- Handle storage responses
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
StorageReceived value ->
case Decode.decodeValue (Decode.field "key" Decode.string) value of
Ok "current-user" ->
handleUserData value model
_ ->
(model, Cmd.none)
-- ... other cases
-- Handle user data with Ipê's decoder
handleUserData : Encode.Value -> Model -> (Model, Cmd Msg)
handleUserData value model =
case Ipe.decodeStorageResult userDecoder value of
Ok user ->
({ model | user = Just user }, Cmd.none)
Err (Ipe.DecodeError error) ->
({ model | error = Just ("Decode error: " ++ Decode.errorToString error) }, Cmd.none)
Err Ipe.NotFound ->
({ model | user = Nothing }, Cmd.none)
```
## API Reference
### Storage Types
```elm
type StorageType
= Local -- localStorage
| Session -- sessionStorage
```
### Error Types
```elm
type Error
= DecodeError Decode.Error -- JSON decoding failed
| NotFound -- Key not found in storage
```
### Core Functions
#### `save : StorageType -> String -> Encode.Value -> Encode.Value`
Create a save command payload.
```elm
-- Create save payload
savePayload = Ipe.save Local "username" (Encode.string "john")
-- Use with your port
savePayload |> saveToStorage
```
#### `load : StorageType -> String -> Encode.Value`
Create a load command payload.
```elm
-- Create load payload
loadPayload = Ipe.load Local "username"
-- Use with your port
loadPayload |> loadFromStorage
```
#### `remove : StorageType -> String -> Encode.Value`
Create a remove command payload.
```elm
-- Create remove payload
removePayload = Ipe.remove Local "username"
-- Use with your port
removePayload |> removeFromStorage
```
#### `decodeStorageResult : Decode.Decoder a -> Encode.Value -> Result Error a`
Decode storage results from JavaScript.
```elm
-- Handle storage response
case Ipe.decodeStorageResult userDecoder storageValue of
Ok user ->
-- Successfully decoded user
Err (DecodeError error) ->
-- Failed to decode
Err NotFound ->
-- Key not found in storage
```
#### `storageTypeToString : StorageType -> String`
Convert storage type to string (for advanced usage).
```elm
Ipe.storageTypeToString Local -- "local"
Ipe.storageTypeToString Session -- "session"
```
## Example Application
Check out the `/example` directory for a complete, beautiful example application that demonstrates:
- Saving and loading user profiles
- Session theme management
- Error handling scenarios
- Modern, responsive UI
- Real-world usage patterns
### Running the Example
```bash
cd example
elm make Main.elm --output=main.js
# Open index.html in your browser
```
## JavaScript Bridge (`storage.js`)
The JavaScript bridge is essential for Ipê to work. It handles the actual browser storage operations and communicates with your Elm application through ports.
### Key Features:
- **Automatic JSON handling** - Serializes/deserializes data automatically
- **Error resilience** - Graceful error handling and logging
- **Storage abstraction** - Works with both localStorage and sessionStorage
- **Type preservation** - Maintains data types when possible
### Integration:
1. Copy the `setupIpePorts` function to your project
2. Call it after initializing your Elm app
3. That's it! Ipê handles the rest
## Project Structure
```
ipe-elm/
├── src/
│ └── Ipe.elm # Main library module
├── example/
│ ├── Main.elm # Example application
│ ├── index.html # Example HTML with styling
│ └── main.js # Compiled example (generated)
├── js/
│ └── storage.js # JavaScript bridge
├── elm.json # Package configuration
└── README.md # This file
```
## Contributing
Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.
### Development Setup
```bash
git clone https://github.com/heitorgandolfi/ipe-elm.git
cd ipe-elm
elm make src/Ipe.elm
```
## Requirements
- Elm 0.19.1+
- Browser with localStorage/sessionStorage support
- JavaScript enabled
## Changelog
### v1.0.0 (Initial Release)
- ✨ Core storage operations (save, load, remove)
- ✨ Support for localStorage and sessionStorage
- ✨ Type-safe error handling
- ✨ Subscription-based updates
- ✨ Complete example application
- ✨ Modern, beautiful UI example
## License
BSD 3-Clause - see [LICENSE](LICENSE) for details.
## Acknowledgments
- Built with ❤️ for the Elm community
- Inspired by the beauty of Brazilian Ipê trees
- Special thanks to all contributors and users
---
Made with 🌸 by the Elm community
Bringing the beauty of Ipê flowers to your Elm applications