{"id":29426565,"url":"https://github.com/heitorgandolfi/ipe-elm","last_synced_at":"2026-04-12T20:36:17.414Z","repository":{"id":302891687,"uuid":"1013857667","full_name":"heitorgandolfi/ipe-elm","owner":"heitorgandolfi","description":"A beautiful, type-safe storage library for Elm applications. Simple, elegant, and powerful.","archived":false,"fork":false,"pushed_at":"2025-07-04T16:44:54.000Z","size":44,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-04T16:47:35.018Z","etag":null,"topics":["elm","elm-lang","elm-ports","javascript-interop","localstorage","sessionstorage"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/heitorgandolfi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-04T15:25:30.000Z","updated_at":"2025-07-04T16:30:58.000Z","dependencies_parsed_at":"2025-07-04T16:57:40.819Z","dependency_job_id":null,"html_url":"https://github.com/heitorgandolfi/ipe-elm","commit_stats":null,"previous_names":["heitorgandolfi/ipe-elm"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/heitorgandolfi/ipe-elm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/heitorgandolfi%2Fipe-elm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/heitorgandolfi%2Fipe-elm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/heitorgandolfi%2Fipe-elm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/heitorgandolfi%2Fipe-elm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/heitorgandolfi","download_url":"https://codeload.github.com/heitorgandolfi/ipe-elm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/heitorgandolfi%2Fipe-elm/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264986971,"owners_count":23693739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elm","elm-lang","elm-ports","javascript-interop","localstorage","sessionstorage"],"created_at":"2025-07-12T12:01:04.508Z","updated_at":"2026-04-12T20:36:12.089Z","avatar_url":"https://github.com/heitorgandolfi.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ipê - Elegant Storage for Elm 🌸\n\n[![Elm Package](https://img.shields.io/badge/elm-package-red.svg)](https://package.elm-lang.org/)\n[![Version](https://img.shields.io/badge/version-1.0.0-yellow.svg)](https://github.com/heitorgandolfi/ipe-elm/releases)\n\n\u003e A beautiful, type-safe storage library for Elm applications. Simple, elegant, and powerful.\n\n## About Ipê\n\nJust like the Ipê tree that blooms magnificently, this library aims to make your Elm applications flourish with elegant and reliable storage capabilities.\n\n## Features\n\n- **Type-safe** - Full Elm type safety for your storage operations\n- **Universal** - Works with both LocalStorage and SessionStorage\n- **Simple API** - Clean, intuitive interface\n- **Zero dependencies** - Lightweight and focused\n- **Modern** - Built for Elm 0.19.1+\n- **Reactive** - Subscription-based data updates\n- **Error handling** - Comprehensive error management\n\n## Installation\n\n```bash\nelm install heitorgandolfi/ipe-elm\n```\n\n## Quick Start\n\n### 1. Add the required ports to your Elm module\n\n```elm\nport module Main exposing (..)\n\nimport Ipe exposing (StorageType(..), Error(..))\nimport Json.Encode as Encode\nimport Json.Decode as Decode\n\n-- Required ports\nport saveToStorage : Encode.Value -\u003e Cmd msg\nport loadFromStorage : Encode.Value -\u003e Cmd msg\nport removeFromStorage : Encode.Value -\u003e Cmd msg\nport receiveStorageResult : (Encode.Value -\u003e msg) -\u003e Sub msg\n\n-- Helper functions to connect Ipê with your ports\nsaveToIpe : StorageType -\u003e String -\u003e Encode.Value -\u003e Cmd msg\nsaveToIpe storageType key value =\n    Ipe.save storageType key value |\u003e saveToStorage\n\nloadFromIpe : StorageType -\u003e String -\u003e Cmd msg\nloadFromIpe storageType key =\n    Ipe.load storageType key |\u003e loadFromStorage\n\nremoveFromIpe : StorageType -\u003e String -\u003e Cmd msg\nremoveFromIpe storageType key =\n    Ipe.remove storageType key |\u003e removeFromStorage\n```\n\n### 2. Set up the JavaScript bridge\n\nCopy this code to your JavaScript file and call `setupIpePorts(app)` after initializing your Elm app:\n\n```javascript\nfunction setupIpePorts(app) {\n  app.ports.saveToStorage.subscribe((payload) =\u003e {\n    try {\n      const { storageType, key, value } = payload;\n      const data = JSON.stringify(value);\n\n      if (storageType === \"local\") {\n        localStorage.setItem(key, data);\n      } else {\n        sessionStorage.setItem(key, data);\n      }\n    } catch (e) {\n      console.error(\"Ipê (save): Failed to save to storage.\", e);\n    }\n  });\n\n  app.ports.loadFromStorage.subscribe((payload) =\u003e {\n    try {\n      const { storageType, key } = payload;\n\n      let data = null;\n      if (storageType === \"local\") {\n        data = localStorage.getItem(key);\n      } else {\n        data = sessionStorage.getItem(key);\n      }\n\n      let parsed = null;\n      if (data !== null) {\n        try {\n          parsed = JSON.parse(data);\n        } catch (parseError) {\n          parsed = data;\n        }\n      }\n\n      app.ports.receiveStorageResult.send({ key, data: parsed });\n    } catch (e) {\n      console.error(\"Ipê (load): Failed to load from storage.\", e);\n    }\n  });\n\n  app.ports.removeFromStorage.subscribe((payload) =\u003e {\n    try {\n      const { storageType, key } = payload;\n\n      if (storageType === \"local\") {\n        localStorage.removeItem(key);\n      } else {\n        sessionStorage.removeItem(key);\n      }\n    } catch (e) {\n      console.error(\"Ipê (remove): Failed to remove from storage.\", e);\n    }\n  });\n}\n\n// Initialize your Elm app and connect the ports\nvar app = Elm.Main.init({ node: document.getElementById('app') });\nsetupIpePorts(app);\n```\n\n### 3. Use Ipê in your Elm code\n\n```elm\ntype Msg\n    = SaveUser\n    | LoadUser\n    | StorageReceived Encode.Value\n\ntype alias User = { name : String, email : String }\n\n-- Save data\nsaveUser : User -\u003e Cmd Msg\nsaveUser user =\n    saveToIpe Local \"current-user\" (encodeUser user)\n\n-- Load data  \nloadUser : Cmd Msg\nloadUser =\n    loadFromIpe Local \"current-user\"\n\n-- Remove data\nremoveUser : Cmd Msg\nremoveUser =\n    removeFromIpe Local \"current-user\"\n\n-- Subscribe to storage events\nsubscriptions : Model -\u003e Sub Msg\nsubscriptions _ =\n    receiveStorageResult StorageReceived\n\n-- Handle storage responses\nupdate : Msg -\u003e Model -\u003e (Model, Cmd Msg)\nupdate msg model =\n    case msg of\n        StorageReceived value -\u003e\n            case Decode.decodeValue (Decode.field \"key\" Decode.string) value of\n                Ok \"current-user\" -\u003e\n                    handleUserData value model\n                _ -\u003e\n                    (model, Cmd.none)\n        \n        -- ... other cases\n\n-- Handle user data with Ipê's decoder\nhandleUserData : Encode.Value -\u003e Model -\u003e (Model, Cmd Msg)\nhandleUserData value model =\n    case Ipe.decodeStorageResult userDecoder value of\n        Ok user -\u003e\n            ({ model | user = Just user }, Cmd.none)\n        \n        Err (Ipe.DecodeError error) -\u003e\n            ({ model | error = Just (\"Decode error: \" ++ Decode.errorToString error) }, Cmd.none)\n        \n        Err Ipe.NotFound -\u003e\n            ({ model | user = Nothing }, Cmd.none)\n```\n\n## API Reference\n\n### Storage Types\n\n```elm\ntype StorageType\n    = Local      -- localStorage\n    | Session    -- sessionStorage\n```\n\n### Error Types\n\n```elm\ntype Error\n    = DecodeError Decode.Error  -- JSON decoding failed\n    | NotFound                  -- Key not found in storage\n```\n\n### Core Functions\n\n#### `save : StorageType -\u003e String -\u003e Encode.Value -\u003e Encode.Value`\n\nCreate a save command payload.\n\n```elm\n-- Create save payload\nsavePayload = Ipe.save Local \"username\" (Encode.string \"john\")\n\n-- Use with your port\nsavePayload |\u003e saveToStorage\n```\n\n#### `load : StorageType -\u003e String -\u003e Encode.Value`\n\nCreate a load command payload.\n\n```elm\n-- Create load payload\nloadPayload = Ipe.load Local \"username\"\n\n-- Use with your port\nloadPayload |\u003e loadFromStorage\n```\n\n#### `remove : StorageType -\u003e String -\u003e Encode.Value`\n\nCreate a remove command payload.\n\n```elm\n-- Create remove payload\nremovePayload = Ipe.remove Local \"username\"\n\n-- Use with your port\nremovePayload |\u003e removeFromStorage\n```\n\n#### `decodeStorageResult : Decode.Decoder a -\u003e Encode.Value -\u003e Result Error a`\n\nDecode storage results from JavaScript.\n\n```elm\n-- Handle storage response\ncase Ipe.decodeStorageResult userDecoder storageValue of\n    Ok user -\u003e\n        -- Successfully decoded user\n        \n    Err (DecodeError error) -\u003e\n        -- Failed to decode\n        \n    Err NotFound -\u003e\n        -- Key not found in storage\n```\n\n#### `storageTypeToString : StorageType -\u003e String`\n\nConvert storage type to string (for advanced usage).\n\n```elm\nIpe.storageTypeToString Local    -- \"local\"\nIpe.storageTypeToString Session  -- \"session\"\n```\n\n## Example Application\n\nCheck out the `/example` directory for a complete, beautiful example application that demonstrates:\n\n- Saving and loading user profiles\n- Session theme management  \n- Error handling scenarios\n- Modern, responsive UI\n- Real-world usage patterns\n\n### Running the Example\n\n```bash\ncd example\nelm make Main.elm --output=main.js\n# Open index.html in your browser\n```\n\n## JavaScript Bridge (`storage.js`)\n\nThe JavaScript bridge is essential for Ipê to work. It handles the actual browser storage operations and communicates with your Elm application through ports.\n\n### Key Features:\n- **Automatic JSON handling** - Serializes/deserializes data automatically\n- **Error resilience** - Graceful error handling and logging\n- **Storage abstraction** - Works with both localStorage and sessionStorage\n- **Type preservation** - Maintains data types when possible\n\n### Integration:\n1. Copy the `setupIpePorts` function to your project\n2. Call it after initializing your Elm app\n3. That's it! Ipê handles the rest\n\n## Project Structure\n\n```\nipe-elm/\n├── src/\n│   └── Ipe.elm              # Main library module\n├── example/\n│   ├── Main.elm              # Example application\n│   ├── index.html            # Example HTML with styling\n│   └── main.js               # Compiled example (generated)\n├── js/\n│   └── storage.js            # JavaScript bridge\n├── elm.json                  # Package configuration\n└── README.md                 # This file\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit issues, feature requests, or pull requests.\n\n### Development Setup\n\n```bash\ngit clone https://github.com/heitorgandolfi/ipe-elm.git\ncd ipe-elm\nelm make src/Ipe.elm\n```\n\n## Requirements\n\n- Elm 0.19.1+\n- Browser with localStorage/sessionStorage support\n- JavaScript enabled\n\n## Changelog\n\n### v1.0.0 (Initial Release)\n- ✨ Core storage operations (save, load, remove)\n- ✨ Support for localStorage and sessionStorage\n- ✨ Type-safe error handling\n- ✨ Subscription-based updates\n- ✨ Complete example application\n- ✨ Modern, beautiful UI example\n\n## License\n\nBSD 3-Clause - see [LICENSE](LICENSE) for details.\n\n## Acknowledgments\n\n- Built with ❤️ for the Elm community\n- Inspired by the beauty of Brazilian Ipê trees\n- Special thanks to all contributors and users\n\n---\n\nMade with 🌸 by the Elm community\nBringing the beauty of Ipê flowers to your Elm applications\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheitorgandolfi%2Fipe-elm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fheitorgandolfi%2Fipe-elm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheitorgandolfi%2Fipe-elm/lists"}