mirror of
https://github.com/plausible/analytics.git
synced 2024-12-29 04:22:34 +03:00
b3ff695797
* Add Heroicons dependency
* Add name_of/1 html helper
Currently with Floki there's no way to query for
`[name=foo[some]]` selector
* Update changelog
* Make goal deletion possible with only goal id
* Remove stale goal controllers
* Improve ComboBox component
- make sure the list options are always of the parent input width
- allow passing a suggestion function instead of a module
* Stale fixup
* Update routes
* Use the new goals route in funnel settings
* Use a function in the funnel combo
* Use function in the props combo
* Remove old goals form
* Implement new goal settings
* Update moduledoc
* Fix revenue switch in dark mode
* Connect live socket on goal settings page
* Fixup
* Use Heroicons.trash icon
* Tweak goals search input
* Remove unused alias
* Fix search/button alignment
* Fix backspace icon alignment
* Delegate :superadmin check to get_for_user/3
I'll do props settings separately, it's work in progress
in a branch on top of this one already. cc @ukutaht
* Rename socket assigns
* Fixup to 5c9f58e
* Fixup
* Render ComboBox suggestions asynchronously
This commit:
- prevents redundant work by checking the socket connection
- allows passing no options to the ComboBox component,
so that when combined with the `async` option, the options
are asynchronously initialized post-render
- allows updating the suggestions asynchronously with the
`async` option set to `true` - helpful in case of DB
queries used for suggestions
* Update tests
* Throttle comboboxes
* Update tests
* Dim the search input
* Use debounce=200 in ComboBox component
* Move creatable option to the top
* Ensure there's always a leading slash for goals
* Test pageview goals with leading / missing
* Make the modal scrollable on small viewports
111 lines
3.0 KiB
Elixir
111 lines
3.0 KiB
Elixir
defmodule PlausibleWeb.Live.Components.Form do
|
|
@moduledoc """
|
|
Generic components stolen from mix phx.new templates
|
|
"""
|
|
|
|
use Phoenix.Component
|
|
|
|
@doc """
|
|
Renders an input with label and error messages.
|
|
|
|
A `Phoenix.HTML.FormField` may be passed as argument,
|
|
which is used to retrieve the input name, id, and values.
|
|
Otherwise all attributes may be passed explicitly.
|
|
|
|
## Examples
|
|
|
|
<.input field={@form[:email]} type="email" />
|
|
<.input name="my-input" errors={["oh no!"]} />
|
|
"""
|
|
attr(:id, :any, default: nil)
|
|
attr(:name, :any)
|
|
attr(:label, :string, default: nil)
|
|
attr(:value, :any)
|
|
|
|
attr(:type, :string,
|
|
default: "text",
|
|
values: ~w(checkbox color date datetime-local email file hidden month number password
|
|
range radio search select tel text textarea time url week)
|
|
)
|
|
|
|
attr(:field, Phoenix.HTML.FormField,
|
|
doc: "a form field struct retrieved from the form, for example: @form[:email]"
|
|
)
|
|
|
|
attr(:errors, :list, default: [])
|
|
attr(:checked, :boolean, doc: "the checked flag for checkbox inputs")
|
|
attr(:prompt, :string, default: nil, doc: "the prompt for select inputs")
|
|
attr(:options, :list, doc: "the options to pass to Phoenix.HTML.Form.options_for_select/2")
|
|
attr(:multiple, :boolean, default: false, doc: "the multiple flag for select inputs")
|
|
|
|
attr(:rest, :global,
|
|
include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
|
|
multiple pattern placeholder readonly required rows size step)
|
|
)
|
|
|
|
slot(:inner_block)
|
|
|
|
def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
|
|
assigns
|
|
|> assign(field: nil, id: assigns.id || field.id)
|
|
|> assign(:errors, Enum.map(field.errors, &translate_error(&1)))
|
|
|> assign_new(:name, fn -> if assigns.multiple, do: field.name <> "[]", else: field.name end)
|
|
|> assign_new(:value, fn -> field.value end)
|
|
|> input()
|
|
end
|
|
|
|
# All other inputs text, datetime-local, url, password, etc. are handled here...
|
|
def input(assigns) do
|
|
~H"""
|
|
<div phx-feedback-for={@name}>
|
|
<.label for={@id}>
|
|
<%= @label %>
|
|
</.label>
|
|
<input
|
|
type={@type}
|
|
name={@name}
|
|
id={@id}
|
|
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
|
|
{@rest}
|
|
/>
|
|
<.error :for={msg <- @errors}>
|
|
<%= msg %>
|
|
</.error>
|
|
</div>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders a label.
|
|
"""
|
|
attr(:for, :string, default: nil)
|
|
slot(:inner_block, required: true)
|
|
|
|
def label(assigns) do
|
|
~H"""
|
|
<label for={@for} class="block font-medium dark:text-gray-100">
|
|
<%= render_slot(@inner_block) %>
|
|
</label>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Generates a generic error message.
|
|
"""
|
|
slot(:inner_block, required: true)
|
|
|
|
def error(assigns) do
|
|
~H"""
|
|
<p class="flex gap-3 text-sm leading-6 text-red-500 phx-no-feedback:hidden">
|
|
<%= render_slot(@inner_block) %>
|
|
</p>
|
|
"""
|
|
end
|
|
|
|
def translate_error({msg, opts}) do
|
|
Enum.reduce(opts, msg, fn {key, value}, acc ->
|
|
String.replace(acc, "%{#{key}}", fn _ -> to_string(value) end)
|
|
end)
|
|
end
|
|
end
|