Skip to content

Commit c7e6073

Browse files
authored
Merge pull request #7 from dmkenney/dev
2 parents bd5c7f6 + 039db83 commit c7e6073

21 files changed

Lines changed: 771 additions & 63 deletions

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.2.0] - 2025-07-28
9+
10+
### Added
11+
- HTML rendering support - Toasts can now render HTML content with the `html` option
12+
- Configurable animation duration - Animation timing can be customized (defaults to 400ms)
13+
14+
### Fixed
15+
- DaisyUI style conflict documentation
16+
817
## [0.1.0] - 2025-07-18
918

1019
Initial release

CONTRIBUTING.md

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# Contributing to Toast
2+
3+
Thank you for your interest in contributing to Toast! This guide will help you get started with contributing to the project.
4+
5+
## Table of Contents
6+
7+
- [Development Setup](#development-setup)
8+
- [Development Workflow](#development-workflow)
9+
- [Testing](#testing)
10+
- [Code Style](#code-style)
11+
- [Submitting Changes](#submitting-changes)
12+
- [Reporting Issues](#reporting-issues)
13+
- [Feature Requests](#feature-requests)
14+
15+
## Development Setup
16+
17+
1. **Fork and clone the repository**
18+
```bash
19+
git clone https://github.com/YOUR_USERNAME/toast.git
20+
cd toast
21+
```
22+
23+
2. **Install dependencies**
24+
```bash
25+
mix deps.get
26+
```
27+
28+
3. **Set up the demo application**
29+
```bash
30+
cd demo
31+
mix setup
32+
```
33+
34+
## Development Workflow
35+
36+
Toast includes a demo application in the `demo/` directory that makes development easier. We've created Mix tasks to streamline the development process:
37+
38+
### Working with Local Changes
39+
40+
1. **Switch to local development mode**
41+
```bash
42+
cd demo
43+
mix mode.local
44+
```
45+
This creates a symlink from `demo/deps/toast` to your local toast project, allowing you to see changes immediately.
46+
47+
2. **Check current mode**
48+
```bash
49+
mix mode
50+
```
51+
This shows whether you're using the local version or the published Hex package.
52+
53+
3. **Switch to published mode**
54+
```bash
55+
mix mode.published
56+
```
57+
This uses the published Hex package, useful for testing the actual release.
58+
59+
### Running the Demo
60+
61+
```bash
62+
cd demo
63+
mix phx.server
64+
```
65+
66+
Visit [`localhost:4000`](http://localhost:4000) to see the demo application with live examples of toast notifications.
67+
68+
## Testing
69+
70+
### Running Tests
71+
72+
```bash
73+
# Run tests in the main project
74+
mix test
75+
76+
# Run tests in the demo
77+
cd demo && mix test
78+
```
79+
80+
### Testing Your Changes
81+
82+
1. Make your changes to the toast library
83+
2. Ensure you're in local mode (`mix mode.local` in the demo directory)
84+
3. Test your changes in the demo application
85+
4. Write or update tests as needed
86+
87+
## Code Style
88+
89+
- Follow standard Elixir conventions
90+
- Run the formatter before committing: `mix format`
91+
- Write descriptive commit messages
92+
93+
### JavaScript Code
94+
95+
- The JavaScript hook is in `assets/js/toast.js`
96+
- Follow existing code patterns and style
97+
98+
### CSS Styles
99+
100+
- Styles are in `assets/css/toast.css`
101+
102+
## Submitting Changes
103+
104+
1. **Create a feature branch from `dev`**
105+
```bash
106+
git checkout dev
107+
git pull origin dev
108+
git checkout -b feature/your-feature-name
109+
```
110+
111+
2. **Make your changes**
112+
- Write clear, focused commits
113+
- Include tests for new functionality
114+
- Update documentation as needed
115+
116+
3. **Ensure all tests pass**
117+
```bash
118+
mix test
119+
mix format --check-formatted
120+
```
121+
122+
4. **Push your branch and create a pull request**
123+
- **IMPORTANT: Target the `dev` branch, not `main`**
124+
- Provide a clear description of your changes
125+
- Reference any related issues
126+
- Include screenshots for UI changes
127+
128+
### Pull Request Guidelines
129+
130+
- **Target Branch**: All PRs should target the `dev` branch
131+
- **Title**: Use a clear, descriptive title
132+
- **Description**: Explain what changes you made and why
133+
- **Testing**: Describe how you tested your changes
134+
- **Breaking Changes**: Clearly note any breaking changes
135+
136+
## Reporting Issues
137+
138+
When reporting issues, please include:
139+
140+
- Elixir/Erlang versions (`elixir --version`)
141+
- Phoenix version
142+
- LiveView version
143+
- Steps to reproduce the issue
144+
- Expected behavior
145+
- Actual behavior
146+
- Any error messages or logs
147+
148+
## Feature Requests
149+
150+
We welcome feature requests! Please:
151+
152+
- Check existing issues to avoid duplicates
153+
- Provide a clear use case
154+
- Explain why the feature would be valuable
155+
- If possible, suggest an implementation approach
156+
157+
## Publishing (Maintainers Only)
158+
159+
When ready to publish a new version:
160+
161+
1. Update the version in `mix.exs`
162+
2. Update the CHANGELOG.md
163+
3. From the demo directory, run:
164+
```bash
165+
cd demo
166+
mix toast_publish
167+
```
168+
This automatically switches the demo to use the published version before publishing.
169+
170+
## Questions?
171+
172+
Feel free to open an issue for any questions about contributing. We're here to help!
173+
174+
Thank you for contributing to Toast! 🍞

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Add `toast` to your list of dependencies in `mix.exs`:
3131
```elixir
3232
def deps do
3333
[
34-
{:toast, "~> 0.1.0"}
34+
{:toast, "~> 0.2.0"}
3535
]
3636
end
3737
```
@@ -146,6 +146,7 @@ Configure the toast container with these attributes:
146146
theme="light"
147147
rich_colors={false}
148148
max_toasts={3}
149+
animation_duration={400}
149150
/>
150151
```
151152

@@ -155,6 +156,7 @@ Configure the toast container with these attributes:
155156
| `theme` | string | `"light"` | Theme style: `"light"` or `"dark"` |
156157
| `rich_colors` | boolean | `false` | Use more vibrant colors for toast types |
157158
| `max_toasts` | integer | `3` | Maximum number of visible toasts |
159+
| `animation_duration` | integer | `400` | Duration of animations in milliseconds |
158160

159161
### Individual Toast Options
160162

@@ -210,6 +212,28 @@ Toast.send_toast(:info, "Custom icon",
210212
)
211213
```
212214

215+
### HTML Content
216+
217+
Toast supports rendering raw HTML in messages, titles, and descriptions using `Phoenix.HTML.raw/1`:
218+
219+
```elixir
220+
# Basic HTML formatting
221+
Toast.send_toast(:info, Phoenix.HTML.raw("<strong>Bold</strong> and <em>italic</em> text"))
222+
223+
# Rich HTML content
224+
Toast.send_toast(:success, Phoenix.HTML.raw("Payment processed"),
225+
title: Phoenix.HTML.raw("Transaction <em>Complete</em>"),
226+
description: Phoenix.HTML.raw("ID: <code>TXN-12345</code>")
227+
)
228+
229+
# Mixed content (some fields escaped, some raw)
230+
Toast.send_toast(:info, "This is escaped: <script>",
231+
description: Phoenix.HTML.raw("This is <strong>HTML</strong>")
232+
)
233+
```
234+
235+
**⚠️ Security Warning**: Only use `Phoenix.HTML.raw/1` with trusted content. Never render user-generated HTML without proper sanitization as it can lead to XSS vulnerabilities.
236+
213237
### Update Existing Toasts
214238

215239
Update a toast after it's displayed:
@@ -257,6 +281,7 @@ Toast uses CSS custom properties for easy theming:
257281
--toast-gap: 15px;
258282
--toast-width: 350px;
259283
--toast-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
284+
--toast-animation-duration: 400ms;
260285
}
261286

262287
/* Override specific toast types */

assets/css/toast.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
width: 356px;
99
max-width: calc(100vw - 32px);
1010
--front-toast-height: 0px;
11+
--toast-animation-duration: 400ms;
1112
gap: 16px;
1213
}
1314

@@ -78,7 +79,7 @@
7879
z-index: var(--z-index);
7980
left: 0;
8081
right: 0;
81-
transition: transform 400ms ease, opacity 400ms ease, height 400ms ease;
82+
transition: transform var(--toast-animation-duration) ease, opacity var(--toast-animation-duration) ease, height var(--toast-animation-duration) ease;
8283
}
8384

8485
/* Top positions use relative positioning for front toast */
@@ -166,7 +167,7 @@
166167

167168
/* Smooth transitions for toast content */
168169
.toast > * {
169-
transition: opacity 400ms ease;
170+
transition: opacity var(--toast-animation-duration) ease;
170171
}
171172

172173
/* All toasts when expanded (hovering) - bottom positions */

assets/js/toast.js

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ export default {
77
this.position = this.el.dataset.position || "bottom-right";
88
this.gap = 15;
99
this.maxToasts = parseInt(this.el.dataset.maxToasts) || null;
10+
this.animationDuration = parseInt(this.el.dataset.animationDuration) || 400;
1011
this.expanded = false;
1112

13+
// Set CSS variable for animation duration
14+
this.el.parentElement.style.setProperty('--toast-animation-duration', `${this.animationDuration}ms`);
15+
1216
// Handle clear-flash events from server
1317
this.handleEvent("clear-flash", ({ key }) => {
1418
const flashEl = document.querySelector(`[data-phx-flash="${key}"]`);
@@ -50,6 +54,22 @@ export default {
5054
updated() {
5155
// Update maxToasts in case it changed
5256
this.maxToasts = parseInt(this.el.dataset.maxToasts) || null;
57+
const newAnimationDuration = parseInt(this.el.dataset.animationDuration) || 400;
58+
59+
// Check if animation duration changed
60+
if (newAnimationDuration !== this.animationDuration) {
61+
this.animationDuration = newAnimationDuration;
62+
63+
// Update CSS variable for animation duration
64+
this.el.parentElement.style.setProperty('--toast-animation-duration', `${this.animationDuration}ms`);
65+
66+
// Update transition on all existing toasts
67+
this.toasts.forEach((toastInfo) => {
68+
if (toastInfo.element && toastInfo.element.getAttribute('data-mounted') === 'true') {
69+
toastInfo.element.style.transition = `all ${this.animationDuration}ms cubic-bezier(0.21, 1.02, 0.73, 1)`;
70+
}
71+
});
72+
}
5373

5474
// Immediately update positions for all toasts when DOM changes
5575
const toastElements = Array.from(this.el.querySelectorAll('[id^="toasts-"]'));
@@ -165,7 +185,7 @@ export default {
165185

166186
// Small delay to ensure layout is settled, then enable transitions and mount
167187
setTimeout(() => {
168-
toastEl.style.transition = "all 400ms cubic-bezier(0.21, 1.02, 0.73, 1)";
188+
toastEl.style.transition = `all ${this.animationDuration}ms cubic-bezier(0.21, 1.02, 0.73, 1)`;
169189
toastEl.setAttribute('data-mounted', 'true');
170190
}, 10);
171191

@@ -356,7 +376,7 @@ export default {
356376
// Wait for animation to complete before removing
357377
setTimeout(() => {
358378
this.removeToastFromServer(toastId);
359-
}, 300); // Animation duration
379+
}, this.animationDuration); // Animation duration
360380
}
361381
} else {
362382
// Show toasts within limit
@@ -396,7 +416,7 @@ export default {
396416

397417
// Also send event to parent LiveView to clear from Phoenix flash
398418
this.pushEvent("lv:clear-flash", { key: flashKey });
399-
}, 300);
419+
}, this.animationDuration);
400420
}
401421
}
402422
});

0 commit comments

Comments
 (0)