analytics/lib/plausible_web/components/billing/pageview_slider.ex
RobertJoonas 22ecbe7bc7
Refactor: Split up the choose_plan LV code (#3637)
* move format_price to Plausible.Billing

* move PlausibleWeb.Components.Billing file to subfolder

* extract new Notice module

* rename test file and module name

* move growth_grandfathered notice to notice.ex

* extract a PlanBenefits module

* extract PlanBox component

* extract PageviewSlider component

* fix plan benefits text color
2023-12-15 13:59:16 -03:00

161 lines
5.2 KiB
Elixir

defmodule PlausibleWeb.Components.Billing.PageviewSlider do
@moduledoc false
use Phoenix.Component
use Phoenix.HTML
def render(assigns) do
~H"""
<.slider_output volume={@selected_volume} available_volumes={@available_volumes} />
<.slider_input selected_volume={@selected_volume} available_volumes={@available_volumes} />
<.slider_styles />
"""
end
attr :volume, :any
attr :available_volumes, :list
defp slider_output(assigns) do
~H"""
<output class="lg:w-1/4 lg:order-1 font-medium text-lg text-gray-600 dark:text-gray-200">
<span :if={@volume != :enterprise}>Up to</span>
<strong id="slider-value" class="text-gray-900 dark:text-gray-100">
<%= format_volume(@volume, @available_volumes) %>
</strong>
monthly pageviews
</output>
"""
end
defp slider_input(assigns) do
slider_labels =
Enum.map(
assigns.available_volumes ++ [:enterprise],
&format_volume(&1, assigns.available_volumes)
)
assigns = assign(assigns, :slider_labels, slider_labels)
~H"""
<form class="max-w-md lg:max-w-none w-full lg:w-1/2 lg:order-2">
<div class="flex items-baseline space-x-2">
<span class="text-xs font-medium text-gray-600 dark:text-gray-200">
<%= List.first(@slider_labels) %>
</span>
<div class="flex-1 relative">
<input
phx-change="slide"
id="slider"
name="slider"
class="shadow mt-8 dark:bg-gray-600 dark:border-none"
type="range"
min="0"
max={length(@available_volumes)}
step="1"
value={
Enum.find_index(@available_volumes, &(&1 == @selected_volume)) ||
length(@available_volumes)
}
oninput="repositionBubble()"
/>
<output
id="slider-bubble"
class="absolute bottom-[35px] py-[4px] px-[12px] -translate-x-1/2 rounded-md text-white bg-indigo-600 position text-xs font-medium"
phx-update="ignore"
/>
</div>
<span class="text-xs font-medium text-gray-600 dark:text-gray-200">
<%= List.last(@slider_labels) %>
</span>
</div>
</form>
<script>
const SLIDER_LABELS = <%= raw Jason.encode!(@slider_labels) %>
function repositionBubble() {
const input = document.getElementById("slider")
const percentage = Number((input.value / input.max) * 100)
const bubble = document.getElementById("slider-bubble")
bubble.innerHTML = SLIDER_LABELS[input.value]
bubble.style.left = `calc(${percentage}% + (${13.87 - percentage * 0.26}px))`
}
repositionBubble()
</script>
"""
end
defp format_volume(volume, available_volumes) do
if volume == :enterprise do
available_volumes
|> List.last()
|> PlausibleWeb.StatsView.large_number_format()
|> Kernel.<>("+")
else
PlausibleWeb.StatsView.large_number_format(volume)
end
end
defp slider_styles(assigns) do
~H"""
<style>
input[type="range"] {
-moz-appearance: none;
-webkit-appearance: none;
background: white;
border-radius: 3px;
height: 6px;
width: 100%;
margin-bottom: 9px;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
appearance: none;
-webkit-appearance: none;
background-color: #5f48ff;
background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2212%22%20height%3D%228%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M8%20.5v7L12%204zM0%204l4%203.5v-7z%22%20fill%3D%22%23FFFFFF%22%20fill-rule%3D%22nonzero%22%2F%3E%3C%2Fsvg%3E");
background-position: center;
background-repeat: no-repeat;
border: 0;
border-radius: 50%;
cursor: pointer;
height: 26px;
width: 26px;
}
input[type="range"]::-moz-range-thumb {
background-color: #5f48ff;
background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2212%22%20height%3D%228%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M8%20.5v7L12%204zM0%204l4%203.5v-7z%22%20fill%3D%22%23FFFFFF%22%20fill-rule%3D%22nonzero%22%2F%3E%3C%2Fsvg%3E");
background-position: center;
background-repeat: no-repeat;
border: 0;
border: none;
border-radius: 50%;
cursor: pointer;
height: 26px;
width: 26px;
}
input[type="range"]::-ms-thumb {
background-color: #5f48ff;
background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2212%22%20height%3D%228%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M8%20.5v7L12%204zM0%204l4%203.5v-7z%22%20fill%3D%22%23FFFFFF%22%20fill-rule%3D%22nonzero%22%2F%3E%3C%2Fsvg%3E");
background-position: center;
background-repeat: no-repeat;
border: 0;
border-radius: 50%;
cursor: pointer;
height: 26px;
width: 26px;
}
input[type="range"]::-moz-focus-outer {
border: 0;
}
</style>
"""
end
end