Upgrade deps, add storybook (#4947)

* Add `<.dropdown_item>`

* Make the ellipsis menu functional again

* Upgrade deps so that storybook can be added

* Add storybook and dropdown story

* Remove lingering warnings/errors

* Add color mode to storybook

* Use new liveview used_input? function

* Alpine improvements

* Add select input to storybook

* Bring back `render_form` for CRM

* Configure eslint so it can see deps

* Remove LiveViewTest patch

* Fix test for phoenix liveview 1.0

* Build assets in prod

* Fix tests

* Attempt to fix lint error

* Add explicit text color to input

* mix format

* Format after merge master

* Add moduledocs

* Only run storybook in production

* Update storybook dependency

* Mix format
This commit is contained in:
Uku Taht 2025-01-13 14:31:18 +02:00 committed by GitHub
parent 32d1783604
commit 6c30f62d5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
148 changed files with 683 additions and 587 deletions

View File

@ -2,5 +2,10 @@
plugins: [Phoenix.LiveView.HTMLFormatter],
import_deps: [:ecto, :ecto_sql, :phoenix],
subdirectories: ["priv/*/migrations"],
inputs: ["*.{heex,ex,exs}", "{config,lib,test,extra}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"]
inputs: [
"*.{heex,ex,exs}",
"{config,lib,test,extra}/**/*.{heex,ex,exs}",
"priv/*/seeds.exs",
"storybook/**/*.exs"
]
]

View File

@ -41,6 +41,7 @@ COPY tracker ./tracker
COPY priv ./priv
COPY lib ./lib
COPY extra ./extra
COPY storybook ./storybook
RUN npm run deploy --prefix ./tracker && \
mix assets.deploy && \

View File

@ -50,6 +50,9 @@
"import/resolver": {
"typescript": {
"alwaysTryTypes": true // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
},
"node": {
"moduleDirectory": ["node_modules", "../deps"]
}
},
"react": {

14
assets/css/storybook.css Normal file
View File

@ -0,0 +1,14 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
/*
* Put your component styling within the Tailwind utilities layer.
* See the https://hexdocs.pm/phoenix_storybook/sandboxing.html guide for more info.
*/
@layer utilities {
* {
font-family: system-ui;
}
}

View File

@ -1,7 +1,11 @@
// eslint-disable-next-line import/no-unresolved
import "phoenix_html"
import Alpine from 'alpinejs'
// eslint-disable-next-line import/no-unresolved
import { Socket } from "phoenix"
// eslint-disable-next-line import/no-unresolved
import { LiveSocket } from "phoenix_live_view"
// eslint-disable-next-line import/no-unresolved
import Alpine from 'alpinejs'
let csrfToken = document.querySelector("meta[name='csrf-token']")
let websocketUrl = document.querySelector("meta[name='websocket-url']")

39
assets/js/storybook.js Normal file
View File

@ -0,0 +1,39 @@
import Alpine from 'alpinejs'
import dropdown from "./liveview/dropdown"
// If your components require any hooks or custom uploaders, or if your pages
// require connect parameters, uncomment the following lines and declare them as
// such:
//
// import * as Hooks from "./hooks";
// import * as Params from "./params";
// import * as Uploaders from "./uploaders";
// (function () {
// window.storybook = { Hooks, Params, Uploaders };
// })();
window.Alpine = Alpine
document.addEventListener('DOMContentLoaded', () => {
window.Alpine.start();
});
document.addEventListener('alpine:init', () => {
window.Alpine.data('dropdown', dropdown)
});
(function () {
window.storybook = {
LiveSocketOptions: {
dom: {
onBeforeElUpdated(from, to) {
if (from._x_dataStack) {
window.Alpine.clone(from, to)
}
}
}
}
};
})();

View File

@ -26,9 +26,6 @@
"d3": "^7.9.0",
"dayjs": "^1.11.7",
"iframe-resizer": "^4.3.2",
"phoenix": "^1.7.2",
"phoenix_html": "^3.3.1",
"phoenix_live_view": "^0.18.18",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-flatpickr": "3.10.5",
@ -9308,17 +9305,6 @@
"node": ">=8"
}
},
"node_modules/phoenix": {
"version": "1.7.2",
"license": "MIT"
},
"node_modules/phoenix_html": {
"version": "3.3.1"
},
"node_modules/phoenix_live_view": {
"version": "0.18.18",
"license": "MIT"
},
"node_modules/picocolors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",

View File

@ -30,9 +30,6 @@
"d3": "^7.9.0",
"dayjs": "^1.11.7",
"iframe-resizer": "^4.3.2",
"phoenix": "^1.7.2",
"phoenix_html": "^3.3.1",
"phoenix_live_view": "^0.18.18",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-flatpickr": "3.10.5",

View File

@ -14,6 +14,7 @@ module.exports = {
"max-w-screen-xl"
],
darkMode: 'class',
important: '.plausible',
theme: {
container: {
center: true,
@ -51,7 +52,6 @@ module.exports = {
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/aspect-ratio'),
plugin(({ addVariant }) => addVariant("phx-no-feedback", [".phx-no-feedback&", ".phx-no-feedback &"])),
plugin(({ addVariant }) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])),
plugin(({ addVariant }) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])),
plugin(({ addVariant }) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])),

View File

@ -20,7 +20,7 @@ config :esbuild,
version: "0.17.11",
default: [
args:
~w(js/app.js js/dashboard.tsx js/embed.host.js js/embed.content.js --bundle --target=es2017 --loader:.js=jsx --outdir=../priv/static/js --define:BUILD_EXTRA=true),
~w(js/app.js js/storybook.js js/dashboard.tsx js/embed.host.js js/embed.content.js --bundle --target=es2017 --loader:.js=jsx --outdir=../priv/static/js --define:BUILD_EXTRA=true),
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
@ -34,6 +34,14 @@ config :tailwind,
--output=../priv/static/css/app.css
),
cd: Path.expand("../assets", __DIR__)
],
storybook: [
args: ~w(
--config=tailwind.config.js
--input=css/storybook.css
--output=../priv/static/css/storybook.css
),
cd: Path.expand("../assets", __DIR__)
]
config :ua_inspector,

View File

@ -8,6 +8,7 @@ config :plausible, PlausibleWeb.Endpoint,
watchers: [
esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]},
tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]},
storybook_tailwind: {Tailwind, :install_and_run, [:storybook, ~w(--watch)]},
npm: ["--prefix", "assets", "run", "typecheck", "--", "--watch", "--preserveWatchOutput"],
npm: [
"run",
@ -21,7 +22,8 @@ config :plausible, PlausibleWeb.Endpoint,
],
patterns: [
~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$},
~r"lib/plausible_web/(controllers|live|components|templates|views|plugs)/.*(ex|heex)$"
~r"lib/plausible_web/(controllers|live|components|templates|views|plugs)/.*(ex|heex)$",
~r"storybook/.*(exs)$"
]
]

View File

@ -969,3 +969,5 @@ unless s3_disabled? do
exports_bucket: s3_env_value.("S3_EXPORTS_BUCKET"),
imports_bucket: s3_env_value.("S3_IMPORTS_BUCKET")
end
config :phoenix_storybook, enabled: env !== "prod"

View File

@ -48,7 +48,7 @@ defmodule PlausibleWeb.Live.FunnelSettings do
<.flash_messages flash={@flash} />
<%= if @setup_funnel? do %>
<%= live_render(
{live_render(
@socket,
PlausibleWeb.Live.FunnelSettings.Form,
id: "funnels-form",
@ -56,7 +56,7 @@ defmodule PlausibleWeb.Live.FunnelSettings do
"domain" => @domain,
"funnel_id" => @funnel_id
}
) %>
)}
<% end %>
<div :if={@goal_count >= Funnel.min_steps()}>
<.live_component

View File

@ -64,7 +64,7 @@ defmodule PlausibleWeb.Live.FunnelSettings.Form do
class="bg-white dark:bg-gray-800 shadow-md rounded px-8 pt-6 pb-8 mb-4 mt-8"
>
<.title class="mb-6">
<%= if @funnel, do: "Edit", else: "Add" %> Funnel
{if @funnel, do: "Edit", else: "Add"} Funnel
</.title>
<.input
@ -136,7 +136,7 @@ defmodule PlausibleWeb.Live.FunnelSettings.Form do
length(@step_ids) > map_size(@selections_made)
}
>
<span><%= if @funnel, do: "Update", else: "Add" %> Funnel</span>
<span>{if @funnel, do: "Update", else: "Add"} Funnel</span>
</.button>
</div>
</.form>

View File

@ -22,11 +22,11 @@ defmodule PlausibleWeb.Live.FunnelSettings.List do
<.table rows={@funnels}>
<:tbody :let={funnel}>
<.td truncate>
<span class="font-medium"><%= funnel.name %></span>
<span class="font-medium">{funnel.name}</span>
</.td>
<.td hide_on_mobile>
<span class="text-gray-500 dark:text-gray-400">
<%= funnel.steps_count %>-step funnel
{funnel.steps_count}-step funnel
</span>
</.td>
<.td actions>

View File

@ -17,7 +17,7 @@ defmodule PlausibleWeb.HelpScoutView do
<%= if @conn.assigns[:error] do %>
<p>
Failed to get details: <%= @error %>
Failed to get details: {@error}
</p>
<% else %>
<div class="status">
@ -25,7 +25,7 @@ defmodule PlausibleWeb.HelpScoutView do
Status
</p>
<p class="value">
<a href={@status_link} target="_blank"><%= @status_label %></a>
<a href={@status_link} target="_blank">{@status_label}</a>
</p>
</div>
@ -34,13 +34,13 @@ defmodule PlausibleWeb.HelpScoutView do
Plan
</p>
<p class="value">
<a href={@plan_link} target="_blank"><%= @plan_label %></a>
<a href={@plan_link} target="_blank">{@plan_label}</a>
</p>
</div>
<div class="sites">
<p class="label">
Owner of <b><a href={@sites_link} target="_blank"><%= @sites_count %> sites</a></b>
Owner of <b><a href={@sites_link} target="_blank">{@sites_count} sites</a></b>
</p>
<p class="value"></p>
</div>
@ -51,7 +51,7 @@ defmodule PlausibleWeb.HelpScoutView do
</p>
<div class="value">
<%= Phoenix.HTML.Format.text_to_html(@notes, escape: true) %>
{PhoenixHTMLHelpers.Format.text_to_html(@notes, escape: true)}
</div>
</div>
<% end %>
@ -64,7 +64,7 @@ defmodule PlausibleWeb.HelpScoutView do
<.layout>
<%= if @conn.assigns[:error] do %>
<p>
Failed to run search: <%= @error %>
Failed to run search: {@error}
</p>
<% else %>
<div class="search">
@ -82,7 +82,7 @@ defmodule PlausibleWeb.HelpScoutView do
onclick={"loadContent('/helpscout/show?#{URI.encode_query(email: user.email, conversation_id: @conversation_id, customer_id: @customer_id)}')"}
href="#"
>
<%= user.email %> (<%= user.sites_count %> sites)
{user.email} ({user.sites_count} sites)
</a>
</li>
</ul>
@ -160,7 +160,7 @@ defmodule PlausibleWeb.HelpScoutView do
<body>
<div id="content">
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</div>
<script type="text/javascript">

View File

@ -33,7 +33,7 @@ end
defmodule Plausible.Billing.Ecto.FeatureList do
@moduledoc """
Ecto type representing a list of features. This is a proxy for
Ecto type representing a list of features. This is a proxy for
`{:array, Plausible.Billing.Ecto.Feature}` and is required for Kaffy to
render the HTML input correctly.
"""
@ -52,15 +52,8 @@ defmodule Plausible.Billing.Ecto.FeatureList do
for mod <- Plausible.Billing.Feature.list(), not mod.free?() do
[
{:safe, ~s(<label style="padding-right: 15px;">)},
Phoenix.HTML.Tag.tag(
:input,
name: Phoenix.HTML.Form.input_name(form, field) <> "[]",
id: Phoenix.HTML.Form.input_id(form, field, mod.name()),
type: "checkbox",
value: mod.name(),
style: "margin-right: 3px;",
checked: mod in features
),
{:safe,
~s(<input type="checkbox" name="#{form.name}[#{field}][]" "#{form.name}_#{field}_#{mod.name()}" value="#{mod.name()}" style="margin-right: 3px;" #{if mod in features, do: "checked", else: ""}>)},
mod.display_name(),
{:safe, ~s(</label>)}
]
@ -68,7 +61,7 @@ defmodule Plausible.Billing.Ecto.FeatureList do
[
{:safe, ~s(<div class="form-group">)},
Phoenix.HTML.Form.label(form, field),
{:safe, ~s(<label for="#{form.name}_#{field}">#{Phoenix.Naming.humanize(field)}</label>)},
{:safe, ~s(<div class="form-control">)},
checkboxes,
{:safe, ~s(</div>)},

View File

@ -25,14 +25,9 @@ defmodule Plausible.Billing.Ecto.Limit do
[
{:safe, ~s(<div class="form-group">)},
Phoenix.HTML.Form.label(form, field),
Phoenix.HTML.Form.number_input(form, field,
class: "form-control",
name: "#{form.name}[#{field}]",
id: "#{form.name}_#{field}",
value: value,
min: -1
),
{:safe, ~s(<label for="#{form.name}_#{field}">#{Phoenix.Naming.humanize(field)}</label>)},
{:safe,
~s(<input id="#{form.name}_#{field}" name="#{form.name}[#{field}]" class="form-control" value="#{value}" min="-1" type="number" />)},
{:safe, ~s(<p class="help_text">Use -1 for unlimited.</p>)},
{:safe, ~s(</div>)}
]

View File

@ -60,7 +60,6 @@ defmodule PlausibleWeb do
use Phoenix.Component
import PlausibleWeb.ErrorHelpers
import PlausibleWeb.Components.Generic
import PlausibleWeb.Live.Components.Form
alias PlausibleWeb.Router.Helpers, as: Routes

View File

@ -114,12 +114,12 @@ defmodule PlausibleWeb.Components.Billing do
class="text-sm dark:text-gray-100"
x-bind:class={"tab === '#{@tab}' ? 'text-indigo-600 dark:text-indigo-500 font-semibold' : 'font-medium'"}
>
<%= @name %>
{@name}
</span>
<span class="flex text-xs text-gray-500 dark:text-gray-400">
<%= if @disabled,
{if @disabled,
do: "Not available",
else: PlausibleWeb.TextHelpers.format_date_range(@date_range) %>
else: PlausibleWeb.TextHelpers.format_date_range(@date_range)}
</span>
</div>
</button>
@ -152,7 +152,7 @@ defmodule PlausibleWeb.Components.Billing do
~H"""
<table class="min-w-full text-gray-900 dark:text-gray-100" {@rest}>
<tbody class="divide-y divide-gray-200 dark:divide-gray-600">
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</tbody>
</table>
"""
@ -168,11 +168,11 @@ defmodule PlausibleWeb.Components.Billing do
~H"""
<tr {@rest}>
<td class={["text-sm py-4 pr-1 sm:whitespace-nowrap text-left", @pad && "pl-6"]}>
<%= @title %>
{@title}
</td>
<td class="text-sm py-4 sm:whitespace-nowrap text-right">
<%= Cldr.Number.to_string!(@usage) %>
<%= if is_number(@limit), do: "/ #{Cldr.Number.to_string!(@limit)}" %>
{Cldr.Number.to_string!(@usage)}
{if is_number(@limit), do: "/ #{Cldr.Number.to_string!(@limit)}"}
</td>
</tr>
"""
@ -186,7 +186,7 @@ defmodule PlausibleWeb.Components.Billing do
>
<h4 class="font-black dark:text-gray-100">Monthly quota</h4>
<div class="py-2 text-xl font-medium dark:text-gray-100">
<%= PlausibleWeb.AuthView.subscription_quota(@subscription, format: :long) %>
{PlausibleWeb.AuthView.subscription_quota(@subscription, format: :long)}
</div>
<.styled_link
:if={
@ -196,7 +196,7 @@ defmodule PlausibleWeb.Components.Billing do
id="#upgrade-or-change-plan-link"
href={Routes.billing_path(PlausibleWeb.Endpoint, :choose_plan)}
>
<%= change_plan_or_upgrade_text(@subscription) %>
{change_plan_or_upgrade_text(@subscription)}
</.styled_link>
</div>
"""
@ -206,13 +206,13 @@ defmodule PlausibleWeb.Components.Billing do
~H"""
<ul class="w-full py-4">
<li>
Up to <b><%= present_limit(@plan, :monthly_pageview_limit) %></b> monthly pageviews
Up to <b>{present_limit(@plan, :monthly_pageview_limit)}</b> monthly pageviews
</li>
<li>
Up to <b><%= present_limit(@plan, :site_limit) %></b> sites
Up to <b>{present_limit(@plan, :site_limit)}</b> sites
</li>
<li>
Up to <b><%= present_limit(@plan, :hourly_api_request_limit) %></b> hourly api requests
Up to <b>{present_limit(@plan, :hourly_api_request_limit)}</b> hourly api requests
</li>
</ul>
"""
@ -258,7 +258,7 @@ defmodule PlausibleWeb.Components.Billing do
@checkout_disabled && "pointer-events-none bg-gray-400 dark:bg-gray-600"
]}
>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</button>
"""
end

View File

@ -76,7 +76,7 @@ defmodule PlausibleWeb.Components.Billing.Notice do
title="Notice"
{@rest}
>
<%= account_label(@current_user, @billable_user) %> does not have access to <%= @feature_mod.display_name() %>. To get access to this feature,
{account_label(@current_user, @billable_user)} does not have access to {@feature_mod.display_name()}. To get access to this feature,
<.upgrade_call_to_action
current_team={@current_team}
current_user={@current_user}
@ -96,7 +96,7 @@ defmodule PlausibleWeb.Components.Billing.Notice do
def limit_exceeded(assigns) do
~H"""
<.notice {@rest} title="Notice">
<%= account_label(@current_user, @billable_user) %> is limited to <%= @limit %> <%= @resource %>. To increase this limit,
{account_label(@current_user, @billable_user)} is limited to {@limit} {@resource}. To increase this limit,
<.upgrade_call_to_action
current_team={@current_team}
current_user={@current_user}
@ -239,7 +239,7 @@ defmodule PlausibleWeb.Components.Billing.Notice do
~H"""
<aside class={@class}>
<.notice title="Pending ownership transfers" class="shadow-md dark:shadow-none mt-4">
<%= @message %> To exclude pending sites from your usage, please go to
{@message} To exclude pending sites from your usage, please go to
<.link href="https://plausible.io/sites" class="whitespace-nowrap font-semibold">
plausible.io/sites
</.link>

View File

@ -19,7 +19,7 @@ defmodule PlausibleWeb.Components.Billing.PageviewSlider do
<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) %>
{format_volume(@volume, @available_volumes)}
</strong>
monthly pageviews
</output>
@ -39,7 +39,7 @@ defmodule PlausibleWeb.Components.Billing.PageviewSlider do
<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) %>
{List.first(@slider_labels)}
</span>
<div class="flex-1 relative">
<input
@ -64,7 +64,7 @@ defmodule PlausibleWeb.Components.Billing.PageviewSlider do
/>
</div>
<span class="text-xs font-medium text-gray-600 dark:text-gray-200">
<%= List.last(@slider_labels) %>
{List.last(@slider_labels)}
</span>
</div>
</form>

View File

@ -28,7 +28,7 @@ defmodule PlausibleWeb.Components.Billing.PlanBenefits do
<ul role="list" class={["mt-8 space-y-3 text-sm leading-6 xl:mt-10", @class]}>
<li :for={benefit <- @benefits} class="flex gap-x-3">
<Heroicons.check class="h-6 w-5 text-indigo-600 dark:text-green-600" />
<%= if is_binary(benefit), do: benefit, else: benefit.(assigns) %>
{if is_binary(benefit), do: benefit, else: benefit.(assigns)}
</li>
</ul>
"""

View File

@ -32,7 +32,7 @@ defmodule PlausibleWeb.Components.Billing.PlanBox do
!@highlight && "text-gray-900 dark:text-gray-100",
@highlight && "text-indigo-600 dark:text-indigo-300"
]}>
<%= String.capitalize(to_string(@kind)) %>
{String.capitalize(to_string(@kind))}
</h3>
<.pill :if={@highlight} text={@highlight} />
</div>
@ -98,7 +98,7 @@ defmodule PlausibleWeb.Components.Billing.PlanBox do
id="highlight-pill"
class="rounded-full bg-indigo-600/10 px-2.5 py-1 text-xs font-semibold leading-5 text-indigo-600 dark:text-indigo-300 dark:ring-1 dark:ring-indigo-300/50"
>
<%= @text %>
{@text}
</p>
</div>
"""
@ -142,7 +142,7 @@ defmodule PlausibleWeb.Components.Billing.PlanBox do
id={"#{@kind}-price-tag-amount"}
class="text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-100"
>
<%= @plan_to_render.monthly_cost |> Plausible.Billing.format_price() %>
{@plan_to_render.monthly_cost |> Plausible.Billing.format_price()}
</span>
<span
id={"#{@kind}-price-tag-interval"}
@ -156,13 +156,13 @@ defmodule PlausibleWeb.Components.Billing.PlanBox do
defp price_tag(%{selected_interval: :yearly} = assigns) do
~H"""
<span class="text-2xl font-bold w-max tracking-tight line-through text-gray-500 dark:text-gray-600 mr-1">
<%= @plan_to_render.monthly_cost |> Money.mult!(12) |> Plausible.Billing.format_price() %>
{@plan_to_render.monthly_cost |> Money.mult!(12) |> Plausible.Billing.format_price()}
</span>
<span
id={"#{@kind}-price-tag-amount"}
class="text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-100"
>
<%= @plan_to_render.yearly_cost |> Plausible.Billing.format_price() %>
{@plan_to_render.yearly_cost |> Plausible.Billing.format_price()}
</span>
<span id={"#{@kind}-price-tag-interval"} class="text-sm font-semibold leading-6 text-gray-600">
/year
@ -234,13 +234,13 @@ defmodule PlausibleWeb.Components.Billing.PlanBox do
<% end %>
<.tooltip :if={@exceeded_plan_limits != [] && @disabled_message}>
<div class="pt-2 text-sm w-full flex items-center text-red-700 dark:text-red-500 justify-center">
<%= @disabled_message %>
{@disabled_message}
<Heroicons.information_circle class="hidden sm:block w-5 h-5 sm:ml-2" />
</div>
<:tooltip_content>
Your usage exceeds the following limit(s):<br /><br />
<p :for={limit <- @exceeded_plan_limits}>
<%= Phoenix.Naming.humanize(limit) %><br />
{Phoenix.Naming.humanize(limit)}<br />
</p>
</:tooltip_content>
</.tooltip>
@ -248,7 +248,7 @@ defmodule PlausibleWeb.Components.Billing.PlanBox do
:if={@disabled_message && @exceeded_plan_limits == []}
class="pt-2 text-sm w-full text-red-700 dark:text-red-500 text-center"
>
<%= @disabled_message %>
{@disabled_message}
</div>
"""
end
@ -337,7 +337,7 @@ defmodule PlausibleWeb.Components.Billing.PlanBox do
@checkout_disabled && "pointer-events-none bg-gray-400 dark:bg-gray-600"
]}
>
<%= @change_plan_link_text %>
{@change_plan_link_text}
</button>
"""
end

View File

@ -34,25 +34,25 @@ defmodule PlausibleWeb.Components.FlowProgress do
:if={idx == @current_step_idx}
class="w-5 h-5 bg-indigo-600 text-white rounded-full flex items-center justify-center font-semibold"
>
<%= idx + 1 %>
{idx + 1}
</div>
<div
:if={idx > @current_step_idx}
class="w-5 h-5 bg-gray-300 text-white dark:bg-gray-800 rounded-full flex items-center justify-center"
>
<%= idx + 1 %>
{idx + 1}
</div>
<span :if={idx < @current_step_idx} class="ml-2 text-gray-500">
<%= step %>
{step}
</span>
<span
:if={idx == @current_step_idx}
class="ml-2 font-semibold text-black dark:text-gray-300"
>
<%= step %>
{step}
</span>
<span :if={idx > @current_step_idx} class="ml-2 text-gray-500">
<%= step %>
{step}
</span>
</div>
<div :if={idx + 1 != length(@steps)} class="flex-1 h-px bg-gray-300 mx-4 dark:bg-gray-800 ">

View File

@ -63,7 +63,7 @@ defmodule PlausibleWeb.Components.Generic do
]}
{@rest}
>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</button>
"""
end
@ -84,7 +84,7 @@ defmodule PlausibleWeb.Components.Generic do
[]
else
[
"data-csrf": Phoenix.HTML.Tag.csrf_token_value(assigns.href),
"data-csrf": Phoenix.Controller.get_csrf_token(),
"data-method": assigns.method,
"data-to": assigns.href
]
@ -126,7 +126,7 @@ defmodule PlausibleWeb.Components.Generic do
{@extra}
{@rest}
>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</.link>
"""
end
@ -178,11 +178,11 @@ defmodule PlausibleWeb.Components.Generic do
</div>
<div class={["w-full", @title && "ml-3"]}>
<h3 :if={@title} class={"font-medium #{@theme.title_text} mb-2"}>
<%= @title %>
{@title}
</h3>
<div class={"#{@theme.body_text}"}>
<p>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</p>
</div>
</div>
@ -216,7 +216,7 @@ defmodule PlausibleWeb.Components.Generic do
class={"text-indigo-600 hover:text-indigo-700 dark:text-indigo-500 dark:hover:text-indigo-600 " <> @class}
{@rest}
>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</.unstyled_link>
"""
end
@ -241,10 +241,11 @@ defmodule PlausibleWeb.Components.Generic do
class="relative inline-block text-left"
>
<button x-ref="button" x-on:click="toggle()" type="button" class={List.first(@button).class}>
<%= render_slot(List.first(@button)) %>
{render_slot(List.first(@button))}
</button>
<div
x-show="open"
x-cloak
x-transition:enter="transition ease-out duration-100"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100"
@ -258,7 +259,7 @@ defmodule PlausibleWeb.Components.Generic do
@menu_class
]}
>
<%= render_slot(List.first(@menu)) %>
{render_slot(List.first(@menu))}
</div>
</div>
"""
@ -293,7 +294,7 @@ defmodule PlausibleWeb.Components.Generic do
data-ui-state={@state}
{@rest}
>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</.unstyled_link>
"""
else
@ -301,7 +302,7 @@ defmodule PlausibleWeb.Components.Generic do
~H"""
<div data-ui-state={@state} class={@class}>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</div>
"""
end
@ -327,7 +328,7 @@ defmodule PlausibleWeb.Components.Generic do
[]
else
[
"data-csrf": Phoenix.HTML.Tag.csrf_token_value(assigns.href),
"data-csrf": Phoenix.Controller.get_csrf_token(),
"data-method": assigns.method,
"data-to": assigns.href
]
@ -350,13 +351,13 @@ defmodule PlausibleWeb.Components.Generic do
{@extra}
{@rest}
>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
<Heroicons.arrow_top_right_on_square class={["opacity-60", @icon_class]} />
</.link>
"""
else
~H"""
<.link class={@class} href={@href} {@extra} {@rest}><%= render_slot(@inner_block) %></.link>
<.link class={@class} href={@href} {@extra} {@rest}>{render_slot(@inner_block)}</.link>
"""
end
end
@ -388,7 +389,7 @@ defmodule PlausibleWeb.Components.Generic do
def settings_tiles(assigns) do
~H"""
<div class="text-gray-900 leading-5 dark:text-gray-100">
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</div>
"""
end
@ -406,12 +407,12 @@ defmodule PlausibleWeb.Components.Generic do
<div class="shadow bg-white dark:bg-gray-800 rounded-md mb-6">
<header class="relative py-4 px-6">
<.title>
<%= render_slot(@title) %>
{render_slot(@title)}
<.docs_info :if={@docs} slug={@docs} />
</.title>
<div class="text-sm mt-px text-gray-500 dark:text-gray-400 leading-5">
<%= render_slot(@subtitle) %>
{render_slot(@subtitle)}
</div>
<%= if @feature_mod do %>
<PlausibleWeb.Components.Site.Feature.toggle
@ -424,7 +425,7 @@ defmodule PlausibleWeb.Components.Generic do
</header>
<div class="pb-4 px-6">
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</div>
</div>
"""
@ -455,7 +456,7 @@ defmodule PlausibleWeb.Components.Generic do
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
>
<%= render_slot(List.first(@tooltip_content)) %>
{render_slot(List.first(@tooltip_content))}
</div>
<div
x-on:click="sticky = true; hovered = true"
@ -463,7 +464,7 @@ defmodule PlausibleWeb.Components.Generic do
x-on:mouseover="hovered = true"
x-on:mouseout="hovered = false"
>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</div>
</div>
"""
@ -500,7 +501,7 @@ defmodule PlausibleWeb.Components.Generic do
~H"""
<ol class="list-disc space-y-1 ml-4 text-sm">
<li :for={item <- @item} class="marker:text-indigo-700 dark:marker:text-indigo-700">
<%= render_slot(item) %>
{render_slot(item)}
</li>
</ol>
"""
@ -520,20 +521,20 @@ defmodule PlausibleWeb.Components.Generic do
>
<div class="p-8">
<.title :if={@title != []}>
<%= render_slot(@title) %>
{render_slot(@title)}
</.title>
<div></div>
<div :if={@subtitle != []} class="text-sm mt-4 leading-6">
<%= render_slot(@subtitle) %>
{render_slot(@subtitle)}
</div>
<div :if={@title != []} class="mt-8">
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</div>
<div :if={@title == []}>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</div>
</div>
<div
@ -541,7 +542,7 @@ defmodule PlausibleWeb.Components.Generic do
class="flex flex-col dark:text-gray-200 border-t border-gray-300 dark:border-gray-700"
>
<div class="p-8">
<%= render_slot(@footer) %>
{render_slot(@footer)}
</div>
</div>
</div>
@ -561,14 +562,14 @@ defmodule PlausibleWeb.Components.Generic do
<table :if={not Enum.empty?(@rows)} class={@width} {@rest}>
<thead :if={@thead != []}>
<tr class="border-b border-gray-200 dark:border-gray-700">
<%= render_slot(@thead) %>
{render_slot(@thead)}
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
<tr :for={item <- @rows} {if @row_attrs, do: @row_attrs.(item), else: %{}}>
<%= render_slot(@tbody, item) %>
{render_slot(@tbody, item)}
</tr>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</tbody>
</table>
"""
@ -605,10 +606,10 @@ defmodule PlausibleWeb.Components.Generic do
{@rest}
>
<div :if={@actions} class="flex gap-2">
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</div>
<div :if={!@actions}>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</div>
</td>
"""
@ -630,7 +631,7 @@ defmodule PlausibleWeb.Components.Generic do
~H"""
<th scope="col" class={[@hide_on_mobile && "hidden md:table-cell", @class]}>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</th>
"""
end
@ -667,7 +668,7 @@ defmodule PlausibleWeb.Components.Generic do
else: "text-gray-900 dark:text-gray-100"
)
]}>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</span>
</div>
"""
@ -743,7 +744,7 @@ defmodule PlausibleWeb.Components.Generic do
</form>
</div>
</div>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</div>
"""
end
@ -754,7 +755,7 @@ defmodule PlausibleWeb.Components.Generic do
def h2(assigns) do
~H"""
<h2 class={[@class || "font-semibold leading-6 text-gray-900 dark:text-gray-100"]}>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</h2>
"""
end
@ -765,7 +766,7 @@ defmodule PlausibleWeb.Components.Generic do
def title(assigns) do
~H"""
<.h2 class={["text-lg font-medium text-gray-900 dark:text-gray-100 leading-7", @class]}>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</.h2>
"""
end

View File

@ -26,12 +26,12 @@ defmodule PlausibleWeb.Components.Site.Feature do
class={@class}
>
<.toggle_submit set_to={@current_setting} disabled?={@disabled?}>
Show <%= @feature_mod.display_name() %> in the Dashboard
Show {@feature_mod.display_name()} in the Dashboard
</.toggle_submit>
</.form>
<div :if={@current_setting}>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</div>
</div>
"""

View File

@ -16,7 +16,7 @@ defmodule PlausibleWeb.Components.TwoFactor do
assigns = assign(assigns, :code, qr_code)
~H"""
<%= Phoenix.HTML.raw(@code) %>
{Phoenix.HTML.raw(@code)}
"""
end
@ -38,25 +38,29 @@ defmodule PlausibleWeb.Components.TwoFactor do
end
assigns = assign(assigns, :input_class, input_class)
assigns = assign(assigns, :field, assigns[:form][assigns[:field]])
~H"""
<div class={[@class, "flex items-center"]}>
<%= Phoenix.HTML.Form.text_input(@form, @field,
autocomplete: "off",
class: @input_class,
oninput:
<input
type="text"
name={@field.name}
value={@field.value}
autocomplete="off"
class={@input_class}
oninput={
if @show_button? do
"this.value=this.value.replace(/[^0-9]/g, ''); if (this.value.length >= 6) document.getElementById('#{@id}').focus()"
else
"this.value=this.value.replace(/[^0-9]/g, '');"
end,
onclick: "this.select();",
oninvalid: @show_button? && "document.getElementById('#{@id}').disabled = false",
maxlength: "6",
placeholder: "••••••",
value: "",
required: "required"
) %>
end
}
onclick="this.select();"
oninvalid={@show_button? && "document.getElementById('#{@id}').disabled = false"}
maxlength="6"
placeholder="••••••"
required="required"
/>
<.button
:if={@show_button?}
type="submit"
@ -142,19 +146,19 @@ defmodule PlausibleWeb.Components.TwoFactor do
</div>
<div class="sm:flex sm:items-start">
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-green-100 sm:mx-0 sm:h-10 sm:w-10">
<%= render_slot(@icon) %>
{render_slot(@icon)}
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left text-gray-900 dark:text-gray-100">
<h3 class="text-lg leading-6 font-medium" id="modal-title">
<%= @title %>
{@title}
</h3>
<%= render_slot(@inner_block, f) %>
{render_slot(@inner_block, f)}
</div>
</div>
</div>
<div class="bg-gray-50 dark:bg-gray-850 px-4 py-3 sm:px-9 sm:flex sm:flex-row-reverse">
<%= render_slot(@buttons) %>
{render_slot(@buttons)}
<.button
type="button"
x-on:click={"#{@state_param} = false"}

View File

@ -57,6 +57,7 @@ defmodule PlausibleWeb.AuthController do
flow = params["flow"] || PlausibleWeb.Flows.register()
render(conn, "activate.html",
error: nil,
has_email_code?: Plausible.Users.has_email_code?(user),
has_any_memberships?: Plausible.Teams.Users.has_sites?(user),
form_submit_url: "/activate?flow=#{flow}"

View File

@ -3,7 +3,6 @@ defmodule PlausibleWeb.Live.ChoosePlan do
LiveView for upgrading to a plan, or changing an existing plan.
"""
use PlausibleWeb, :live_view
use Phoenix.HTML
require Plausible.Billing.Subscription.Status
@ -107,9 +106,9 @@ defmodule PlausibleWeb.Live.ChoosePlan do
<Notice.upgrade_ineligible :if={not Quota.eligible_for_upgrade?(@usage)} />
<div class="mx-auto max-w-4xl text-center">
<p class="text-4xl font-bold tracking-tight lg:text-5xl">
<%= if @owned_plan,
{if @owned_plan,
do: "Change subscription plan",
else: "Upgrade your account" %>
else: "Upgrade your account"}
</p>
</div>
<div class="mt-12 flex flex-col gap-8 lg:flex-row items-center lg:items-baseline">

View File

@ -253,9 +253,9 @@ defmodule PlausibleWeb.Live.Components.ComboBox do
class="block truncate py-2 px-3"
>
<%= if @creatable do %>
Create "<%= @display_value %>"
Create "{@display_value}"
<% else %>
<%= @display_value %>
{@display_value}
<% end %>
</a>
</li>

View File

@ -18,7 +18,7 @@ defmodule PlausibleWeb.Live.Components.Form do
<.input name="my-input" errors={["oh no!"]} />
"""
@default_input_class "text-sm dark:bg-gray-900 block pl-3.5 py-2.5 border-gray-300 dark:border-gray-500 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 rounded-md"
@default_input_class "text-sm text-gray-900 dark:text-white dark:bg-gray-900 block pl-3.5 py-2.5 border-gray-300 dark:border-gray-500 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 rounded-md"
attr(:id, :any, default: nil)
attr(:name, :any)
@ -55,6 +55,8 @@ defmodule PlausibleWeb.Live.Components.Form do
slot(:inner_block)
def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
errors = if Phoenix.Component.used_input?(field), do: field.errors, else: []
assigns
|> assign(
field: nil,
@ -63,7 +65,7 @@ defmodule PlausibleWeb.Live.Components.Form do
mt?: assigns.mt?,
width: assigns.width
)
|> assign(:errors, Enum.map(field.errors, &translate_error(&1)))
|> assign(:errors, Enum.map(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()
@ -71,27 +73,27 @@ defmodule PlausibleWeb.Live.Components.Form do
def input(%{type: "select"} = assigns) do
~H"""
<div phx-feedback-for={@name} class={@mt? && "mt-2"}>
<.label for={@id} class="mb-2"><%= @label %></.label>
<div class={@mt? && "mt-2"}>
<.label for={@id} class="mb-2">{@label}</.label>
<p :if={@help_text} class="text-gray-500 dark:text-gray-400 mb-2 text-sm">
<%= @help_text %>
{@help_text}
</p>
<select id={@id} name={@name} multiple={@multiple} class={[@class, @width]} {@rest}>
<option :if={@prompt} value=""><%= @prompt %></option>
<%= Phoenix.HTML.Form.options_for_select(@options, @value) %>
<option :if={@prompt} value="">{@prompt}</option>
{Phoenix.HTML.Form.options_for_select(@options, @value)}
</select>
<.error :for={msg <- @errors}><%= msg %></.error>
<.error :for={msg <- @errors}>{msg}</.error>
</div>
"""
end
def input(%{type: "checkbox"} = assigns) do
~H"""
<div
phx-feedback-for={@name}
class={["flex flex-inline items-center sm:justify-start justify-center gap-x-2", @mt? && "mt-2"]}
>
<div class={[
"flex flex-inline items-center sm:justify-start justify-center gap-x-2",
@mt? && "mt-2"
]}>
<input
type="checkbox"
value={@value || "true"}
@ -99,7 +101,7 @@ defmodule PlausibleWeb.Live.Components.Form do
name={@name}
class="block h-5 w-5 rounded dark:bg-gray-700 border-gray-300 text-indigo-600 focus:ring-indigo-600"
/>
<.label for={@id}><%= @label %></.label>
<.label for={@id}>{@label}</.label>
</div>
"""
end
@ -116,12 +118,12 @@ defmodule PlausibleWeb.Live.Components.Form do
assigns = assign(assigns, :errors, errors)
~H"""
<div phx-feedback-for={@name} class={@mt? && "mt-2"}>
<div class={@mt? && "mt-2"}>
<.label :if={@label != nil and @label != ""} for={@id} class="mb-2">
<%= @label %>
{@label}
</.label>
<p :if={@help_text} class="text-gray-500 dark:text-gray-400 mb-2 text-sm">
<%= @help_text %>
{@help_text}
</p>
<input
type={@type}
@ -131,9 +133,9 @@ defmodule PlausibleWeb.Live.Components.Form do
class={[@class, @width, assigns[:rest][:disabled] && "text-gray-500 dark:text-gray-400"]}
{@rest}
/>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
<.error :for={msg <- @errors}>
<%= msg %>
{msg}
</.error>
</div>
"""
@ -153,7 +155,7 @@ defmodule PlausibleWeb.Live.Components.Form do
<div>
<div :if={@label}>
<.label for={@id} class="mb-2">
<%= @label %>
{@label}
</.label>
</div>
<div class="relative">
@ -218,10 +220,14 @@ defmodule PlausibleWeb.Live.Components.Form do
|> assign(:too_weak?, too_weak?)
|> assign(:field, %{field | errors: errors})
|> assign(:strength, strength)
|> assign(
:show_meter?,
Phoenix.Component.used_input?(field) && (too_weak? || strength.score > 0)
)
~H"""
<.input field={@field} type="password" autocomplete="new-password" label={@label} id={@id} {@rest}>
<.strength_meter :if={@too_weak? or @strength.score > 0} {@strength} />
<.strength_meter :if={@show_meter?} {@strength} />
</.input>
"""
end
@ -256,7 +262,7 @@ defmodule PlausibleWeb.Live.Components.Form do
assigns = assign(assigns, :class, final_class)
~H"""
<p class={@class}>Min <%= @minimum %> characters</p>
<p class={@class}>Min {@minimum} characters</p>
"""
end
@ -311,11 +317,11 @@ defmodule PlausibleWeb.Live.Components.Form do
>
</div>
</div>
<p :if={@score <= 2} class="text-sm text-red-500 phx-no-feedback:hidden">
<p :if={@score <= 2} class="text-sm text-red-500">
Password is too weak
</p>
<p :if={@feedback} class="text-xs text-gray-500">
<%= @feedback %>
{@feedback}
</p>
"""
end
@ -330,7 +336,7 @@ defmodule PlausibleWeb.Live.Components.Form do
def label(assigns) do
~H"""
<label for={@for} class={["text-sm block font-medium dark:text-gray-100", @class]}>
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</label>
"""
end
@ -342,8 +348,8 @@ defmodule PlausibleWeb.Live.Components.Form do
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 class="flex gap-3 text-sm leading-6 text-red-500">
{render_slot(@inner_block)}
</p>
"""
end

View File

@ -260,7 +260,7 @@ defmodule PlausibleWeb.Live.Components.Modal do
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-on:click.outside="closeModal()"
>
<%= render_slot(@inner_block, modal_unique_id(@modal_sequence_id)) %>
{render_slot(@inner_block, modal_unique_id(@modal_sequence_id))}
</Phoenix.Component.focus_wrap>
<div x-show="modalOpen" class="modal-loading hidden w-full self-center">
<div class="text-center">

View File

@ -12,7 +12,7 @@ defmodule PlausibleWeb.Live.Components.Pagination do
>
<div class="hidden sm:block">
<p class="text-sm text-gray-700 dark:text-gray-300">
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</p>
</div>
<div class="flex-1 flex justify-between sm:justify-end">

View File

@ -59,7 +59,7 @@ defmodule PlausibleWeb.Live.Components.Verification do
<span :if={not @finished?}>Verifying your installation</span>
<span :if={@finished? and not @success? and @interpretation}>
<%= List.first(@interpretation.errors) %>
{List.first(@interpretation.errors)}
</span>
</.title>
<p :if={@finished? and @success?} id="progress" class="text-sm mt-4">
@ -67,19 +67,19 @@ defmodule PlausibleWeb.Live.Components.Verification do
</p>
<p
:if={@finished? and @success? and @awaiting_first_pageview?}
id="progress"
id="awaiting"
class="text-sm mt-4 animate-pulse"
>
Awaiting your first pageview
</p>
<p :if={not @finished?} class="text-sm mt-4 animate-pulse" id="progress"><%= @message %></p>
<p :if={not @finished?} class="text-sm mt-4 animate-pulse" id="progress">{@message}</p>
<p
:if={@finished? and not @success? and @interpretation}
class="mt-4 text-sm text-ellipsis overflow-hidden"
id="recommendation"
>
<span><%= List.first(@interpretation.recommendations).text %>.&nbsp;</span>
<span>{List.first(@interpretation.recommendations).text}.&nbsp;</span>
<.styled_link href={List.first(@interpretation.recommendations).url} new_tab={true}>
Learn more
</.styled_link>
@ -145,7 +145,7 @@ defmodule PlausibleWeb.Live.Components.Verification do
<.focus_list>
<:item :for={{diag, value} <- Map.from_struct(@verification_state.diagnostics)}>
<span class="text-sm">
<%= Phoenix.Naming.humanize(diag) %>: <span class="font-mono"><%= value %></span>
{Phoenix.Naming.humanize(diag)}: <span class="font-mono">{value}</span>
</span>
</:item>
</.focus_list>

View File

@ -173,7 +173,7 @@ defmodule PlausibleWeb.Live.CSVExport do
<:tbody :let={export}>
<.td>
<.styled_link href={@href}>
<%= export.name %>
{export.name}
</.styled_link>
</.td>
<.td actions>
@ -188,14 +188,14 @@ defmodule PlausibleWeb.Live.CSVExport do
<p :if={@export.expires_at} class="text-sm">
Note: this file will expire
<.hint message={@export.expires_at}>
<%= Timex.Format.DateTime.Formatters.Relative.format!(@export.expires_at, "{relative}") %>.
{Timex.Format.DateTime.Formatters.Relative.format!(@export.expires_at, "{relative}")}.
</.hint>
</p>
<p :if={@storage == "local"} class="text-sm">
Located at
<.hint message={@export.path}><%= format_path(@export.path) %></.hint>
(<%= format_bytes(@export.size) %>)
<.hint message={@export.path}>{format_path(@export.path)}</.hint>
({format_bytes(@export.size)})
</p>
"""
end
@ -203,7 +203,7 @@ defmodule PlausibleWeb.Live.CSVExport do
defp hint(assigns) do
~H"""
<span title={@message} class="underline cursor-help underline-offset-2 decoration-dashed">
<%= render_slot(@inner_block) %>
{render_slot(@inner_block)}
</span>
"""
end

View File

@ -87,7 +87,7 @@ defmodule PlausibleWeb.Live.CSVImport do
original={@original_date_range}
/>
<p :for={error <- upload_errors(@uploads.import)} class="text-red-400">
<%= error_to_string(error) %>
{error_to_string(error)}
</p>
</form>
</div>
@ -151,8 +151,8 @@ defmodule PlausibleWeb.Live.CSVImport do
defp dates(assigns) do
~H"""
<span class="whitespace-nowrap">
<span class="font-medium"><%= @range.first %></span>
to <span class="font-medium"><%= @range.last %></span>
<span class="font-medium">{@range.first}</span>
to <span class="font-medium">{@range.last}</span>
</span>
"""
end
@ -182,15 +182,15 @@ defmodule PlausibleWeb.Live.CSVImport do
if(@status == :error, do: "text-red-600 dark:text-red-700")
]}>
<%= if @upload do %>
<%= @upload.client_name %>
{@upload.client_name}
<% else %>
<%= @table %>_YYYYMMDD_YYYYMMDD.csv
{@table}_YYYYMMDD_YYYYMMDD.csv
<% end %>
</span>
</div>
<p :for={error <- @errors} class="ml-6 text-sm text-red-600 dark:text-red-700">
<%= error_to_string(error) %>
{error_to_string(error)}
</p>
</li>
"""

View File

@ -55,10 +55,10 @@ defmodule PlausibleWeb.Live.Flash do
<.icon_success />
</:icon>
<:title>
<%= Flash.get(@flash, :success_title) || "Success!" %>
{Flash.get(@flash, :success_title) || "Success!"}
</:title>
<:message>
<%= Flash.get(@flash, :success) %>
{Flash.get(@flash, :success)}
</:message>
</.flash>
<.flash :if={Flash.get(@flash, :error)} key="error">
@ -66,10 +66,10 @@ defmodule PlausibleWeb.Live.Flash do
<.icon_error />
</:icon>
<:title>
<%= Flash.get(@flash, :error_title) || "Error!" %>
{Flash.get(@flash, :error_title) || "Error!"}
</:title>
<:message>
<%= Flash.get(@flash, :error) %>
{Flash.get(@flash, :error)}
</:message>
</.flash>
<.flash
@ -96,7 +96,7 @@ defmodule PlausibleWeb.Live.Flash do
end
slot(:icon, required: true)
slot(:title, require: true)
slot(:title, required: true)
slot(:message, required: true)
attr(:key, :string, default: nil)
attr(:on_close, :any, default: "lv:clear-flash")
@ -115,13 +115,13 @@ defmodule PlausibleWeb.Live.Flash do
<div class="rounded-lg ring-1 ring-black ring-opacity-5 overflow-hidden">
<div class="p-4">
<div class="flex items-start">
<%= render_slot(@icon) %>
{render_slot(@icon)}
<div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">
<%= render_slot(@title) %>
{render_slot(@title)}
</p>
<p class="mt-1 text-sm leading-5 text-gray-500 dark:text-gray-200">
<%= render_slot(@message) %>
{render_slot(@message)}
</p>
</div>
<div class="ml-4 flex-shrink-0 flex">

View File

@ -56,8 +56,8 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
def render(assigns) do
~H"""
<div id={@id}>
<%= if @goal, do: edit_form(assigns) %>
<%= if is_nil(@goal), do: create_form(assigns) %>
{if @goal, do: edit_form(assigns)}
{if is_nil(@goal), do: create_form(assigns)}
</div>
"""
end
@ -65,7 +65,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
def edit_form(assigns) do
~H"""
<.form :let={f} for={@form} phx-submit="save-goal" phx-target={@myself}>
<.title>Edit Goal for <%= @domain %></.title>
<.title>Edit Goal for {@domain}</.title>
<.custom_event_fields
:if={@selected_tab == "custom_events"}
@ -105,7 +105,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
>
<.spinner class="spinner block absolute right-9 top-8" x-show="tabSelectionInProgress" />
<.title>Add Goal for <%= @domain %></.title>
<.title>Add Goal for {@domain}</.title>
<.tabs selected_tab={@selected_tab} myself={@myself} />
@ -145,7 +145,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
phx-target={@myself}
>
<span :if={@event_name_options_count > 1}>
Already sending custom events? We've found <%= @event_name_options_count %> custom events from the last 6 months that are not yet configured as goals. Click here to add them.
Already sending custom events? We've found {@event_name_options_count} custom events from the last 6 months that are not yet configured as goals. Click here to add them.
</span>
<span :if={@event_name_options_count == 1}>
Already sending custom events? We've found 1 custom event from the last 6 months that is not yet configured as a goal. Click here to add it.
@ -182,7 +182,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
/>
<.error :for={msg <- Enum.map(@f[:page_path].errors, &translate_error/1)}>
<%= msg %>
{msg}
</.error>
<.input
@ -241,7 +241,7 @@ defmodule PlausibleWeb.Live.GoalSettings.Form do
/>
<.error :for={msg <- Enum.map(@f[:event_name].errors, &translate_error/1)}>
<%= msg %>
{msg}
</.error>
</div>

View File

@ -36,7 +36,7 @@ defmodule PlausibleWeb.Live.GoalSettings.List do
<div class="truncate block">
<%= if not @revenue_goals_enabled? && goal.currency do %>
<div class="truncate">
<%= goal %>
{goal}
<br />
<span class="text-red-600">
Unlock Revenue Goals by upgrading to a business plan
@ -44,7 +44,7 @@ defmodule PlausibleWeb.Live.GoalSettings.List do
</div>
<% else %>
<.goal_description goal={goal} />
<span><%= goal %></span>
<span>{goal}</span>
<% end %>
</div>
</div>
@ -115,11 +115,11 @@ defmodule PlausibleWeb.Live.GoalSettings.List do
def goal_description(assigns) do
~H"""
<span :if={@goal.page_path} class="block truncate text-gray-400 dark:text-gray-600">
<%= pageview_description(@goal) %>
{pageview_description(@goal)}
</span>
<span :if={@goal.event_name} class="block truncate text-gray-400 dark:text-gray-600">
<%= custom_event_description(@goal) %>
{custom_event_description(@goal)}
</span>
"""
end

View File

@ -68,7 +68,7 @@ defmodule PlausibleWeb.Live.ImportsExportsSettings do
~H"""
<.notice :if={@import_warning} theme={:gray}>
<%= @import_warning %>
{@import_warning}
</.notice>
<div class="mt-4 flex justify-end gap-x-4">
@ -132,24 +132,22 @@ defmodule PlausibleWeb.Live.ImportsExportsSettings do
class="max-w-sm"
title={"#{Plausible.Imported.SiteImport.label(entry.site_import)} created at #{format_date(entry.site_import.inserted_at)}"}
>
<%= Plausible.Imported.SiteImport.label(entry.site_import) %>
{Plausible.Imported.SiteImport.label(entry.site_import)}
</div>
</div>
</.td>
<.td hide_on_mobile>
<%= format_date(entry.site_import.start_date) %> - <%= format_date(
entry.site_import.end_date
) %>
{format_date(entry.site_import.start_date)} - {format_date(entry.site_import.end_date)}
</.td>
<.td>
<div class="text-right">
<%= if entry.live_status == SiteImport.completed(),
{if entry.live_status == SiteImport.completed(),
do:
PlausibleWeb.StatsView.large_number_format(
pageview_count(entry.site_import, @pageview_counts)
) %>
)}
</div>
</.td>
<.td actions>

View File

@ -293,12 +293,12 @@ defmodule PlausibleWeb.Live.Installation do
class="block h-5 w-5 rounded dark:bg-gray-700 border-gray-300 text-indigo-600 focus:ring-indigo-600 mr-2"
/>
<label for={"check-#{@variant}"}>
<%= @label %>
{@label}
</label>
<div class="ml-2 collapse md:visible">
<.tooltip sticky?={false}>
<:tooltip_content>
<%= @tooltip %>
{@tooltip}
<br /><br />Click to learn more.
</:tooltip_content>
<a href={@learn_more} target="_blank" rel="noopener noreferrer">

View File

@ -35,7 +35,7 @@ defmodule PlausibleWeb.Live.Plugins.API.Settings do
<.flash_messages flash={@flash} />
<%= if @add_token? do %>
<%= live_render(
{live_render(
@socket,
PlausibleWeb.Live.Plugins.API.TokenForm,
id: "token-form",
@ -44,7 +44,7 @@ defmodule PlausibleWeb.Live.Plugins.API.Settings do
"token_description" => @token_description,
"rendered_by" => self()
}
) %>
)}
<% end %>
<div>
@ -64,14 +64,14 @@ defmodule PlausibleWeb.Live.Plugins.API.Settings do
<:tbody :let={token}>
<.td>
<span class="token-description">
<%= token.description %>
{token.description}
</span>
</.td>
<.td hide_on_mobile>
**********<%= token.hint %>
**********{token.hint}
</.td>
<.td hide_on_mobile>
<%= Plausible.Plugins.API.Token.last_used_humanize(token) %>
{Plausible.Plugins.API.Token.last_used_humanize(token)}
</.td>
<.td actions>
<.delete_button

View File

@ -58,7 +58,7 @@ defmodule PlausibleWeb.Live.Plugins.API.TokenForm do
phx-click-away="cancel-add-token"
>
<.title>
Add Plugin Token for <%= @domain %>
Add Plugin Token for {@domain}
</.title>
<div class="mt-4">

View File

@ -39,7 +39,7 @@ defmodule PlausibleWeb.Live.PropsSettings do
<section id="props-settings-main">
<.flash_messages flash={@flash} />
<%= if @add_prop? do %>
<%= live_render(
{live_render(
@socket,
PlausibleWeb.Live.PropsSettings.Form,
id: "props-form",
@ -48,7 +48,7 @@ defmodule PlausibleWeb.Live.PropsSettings do
"site_id" => @site_id,
"rendered_by" => self()
}
) %>
)}
<% end %>
<.live_component

View File

@ -53,7 +53,7 @@ defmodule PlausibleWeb.Live.PropsSettings.Form do
phx-submit="allow-prop"
phx-click-away="cancel-allow-prop"
>
<.title>Add Property for <%= @domain %></.title>
<.title>Add Property for {@domain}</.title>
<div class="mt-6">
<.label for="prop_input">
@ -89,9 +89,9 @@ defmodule PlausibleWeb.Live.PropsSettings.Form do
/>
<.error :for={{msg, opts} <- f[:allowed_event_props].errors}>
<%= Enum.reduce(opts, msg, fn {key, value}, acc ->
{Enum.reduce(opts, msg, fn {key, value}, acc ->
String.replace(acc, "%{#{key}}", fn _ -> to_string(value) end)
end) %>
end)}
</.error>
</div>
@ -105,7 +105,7 @@ defmodule PlausibleWeb.Live.PropsSettings.Form do
class="mt-4 text-sm hover:underline text-indigo-600 dark:text-indigo-400 text-left"
phx-click="allow-existing-props"
>
Already sending custom properties? Click to add <%= @prop_key_options_count %> existing properties we found.
Already sending custom properties? Click to add {@prop_key_options_count} existing properties we found.
</button>
</.form>
</div>

View File

@ -19,7 +19,7 @@ defmodule PlausibleWeb.Live.PropsSettings.List do
<%= if is_list(@props) && length(@props) > 0 do %>
<.table id="allowed-props" rows={Enum.with_index(@props)}>
<:tbody :let={{prop, index}}>
<.td id={"prop-#{index}"}><span class="font-medium"><%= prop %></span></.td>
<.td id={"prop-#{index}"}><span class="font-medium">{prop}</span></.td>
<.td actions>
<.delete_button
id={"disallow-prop-#{prop}"}

View File

@ -42,7 +42,7 @@ defmodule PlausibleWeb.Live.RegisterForm do
def render(%{invitation_expired: true} = assigns) do
~H"""
<div class="mx-auto mt-6 text-center dark:text-gray-300">
<h1 class="text-3xl font-black"><%= Plausible.product_name() %></h1>
<h1 class="text-3xl font-black">{Plausible.product_name()}</h1>
<div class="text-xl font-medium">Lightweight and privacy-friendly web analytics</div>
</div>
@ -63,7 +63,7 @@ defmodule PlausibleWeb.Live.RegisterForm do
<div class="mx-auto text-center dark:text-gray-300">
<h1 class="text-3xl font-black">
<%= if ce?() or @live_action == :register_from_invitation_form do %>
Register your <%= Plausible.product_name() %> account
Register your {Plausible.product_name()} account
<% else %>
Register your 30-day free trial
<% end %>
@ -155,7 +155,7 @@ defmodule PlausibleWeb.Live.RegisterForm do
</div>
<%= if @captcha_error do %>
<div class="text-red-500 text-xs italic mt-3" x-data x-init="hcaptcha.reset()">
<%= @captcha_error %>
{@captcha_error}
</div>
<% end %>
<script
@ -176,7 +176,7 @@ defmodule PlausibleWeb.Live.RegisterForm do
"Start my free trial"
end %>
<.button id="register" disabled={@disable_submit} type="submit" class="mt-4 w-full">
<%= submit_text %>
{submit_text}
</.button>
<p class="text-center text-gray-600 dark:text-gray-500 mt-4">

View File

@ -53,7 +53,7 @@ defmodule PlausibleWeb.Live.Shields.CountryRules do
theme={:gray}
>
<p>
You've reached the maximum number of countries you can block (<%= Shields.maximum_country_rules() %>). Please remove one before adding another.
You've reached the maximum number of countries you can block ({Shields.maximum_country_rules()}). Please remove one before adding another.
</p>
</.notice>
@ -76,7 +76,7 @@ defmodule PlausibleWeb.Live.Shields.CountryRules do
class="mr-4 cursor-help"
title={"Added at #{format_added_at(rule.inserted_at, @site.timezone)} by #{rule.added_by}"}
>
<%= country.flag %> <%= country.name %>
{country.flag} {country.name}
</span>
</div>
</.td>

View File

@ -9,8 +9,6 @@ defmodule PlausibleWeb.Live.Shields.HostnameRules do
alias Plausible.Shields
alias Plausible.Shield
import PlausibleWeb.ErrorHelpers
def update(assigns, socket) do
socket =
socket
@ -58,7 +56,7 @@ defmodule PlausibleWeb.Live.Shields.HostnameRules do
theme={:gray}
>
<p>
You've reached the maximum number of hostnames you can block (<%= Shields.maximum_hostname_rules() %>). Please remove one before adding another.
You've reached the maximum number of hostnames you can block ({Shields.maximum_hostname_rules()}). Please remove one before adding another.
</p>
</.notice>
@ -83,7 +81,7 @@ defmodule PlausibleWeb.Live.Shields.HostnameRules do
class="mr-4 cursor-help text-ellipsis truncate max-w-xs"
title={"Added at #{format_added_at(rule.inserted_at, @site.timezone)} by #{rule.added_by}"}
>
<%= rule.hostname %>
{rule.hostname}
</span>
</div>
</.td>
@ -136,12 +134,11 @@ defmodule PlausibleWeb.Live.Shields.HostnameRules do
id={"#{f[:hostname].id}-#{modal_unique_id}"}
creatable
/>
<%= error_tag(f, :hostname) %>
<.error :for={msg <- f[:hostname].errors}>{translate_error(msg)}</.error>
<p class="mt-4 text-sm text-gray-500 dark:text-gray-400">
You can use a wildcard (<code>*</code>) to match multiple hostnames. For example,
<code>*<%= @site.domain %></code>
<code>*{@site.domain}</code>
will only record traffic on your main domain and all of its subdomains.<br /><br />
<%= if @hostname_rules_count >= 1 do %>

View File

@ -51,7 +51,7 @@ defmodule PlausibleWeb.Live.Shields.IPRules do
theme={:gray}
>
<p>
You've reached the maximum number of IP addresses you can block (<%= Shields.maximum_ip_rules() %>). Please remove one before adding another.
You've reached the maximum number of IP addresses you can block ({Shields.maximum_ip_rules()}). Please remove one before adding another.
</p>
</.notice>
@ -83,7 +83,7 @@ defmodule PlausibleWeb.Live.Shields.IPRules do
class="cursor-help"
title={"Added at #{format_added_at(rule.inserted_at, @site.timezone)} by #{rule.added_by}"}
>
<%= rule.inet %>
{rule.inet}
</span>
</div>
</.td>
@ -97,7 +97,7 @@ defmodule PlausibleWeb.Live.Shields.IPRules do
</.td>
<.td hide_on_mobile truncate>
<span :if={rule.description} title={rule.description}>
<%= rule.description %>
{rule.description}
</span>
<span :if={!rule.description} class="text-gray-400 dark:text-gray-600">
--

View File

@ -9,8 +9,6 @@ defmodule PlausibleWeb.Live.Shields.PageRules do
alias Plausible.Shields
alias Plausible.Shield
import PlausibleWeb.ErrorHelpers
def update(assigns, socket) do
socket =
socket
@ -58,7 +56,7 @@ defmodule PlausibleWeb.Live.Shields.PageRules do
theme={:gray}
>
<p>
You've reached the maximum number of pages you can block (<%= Shields.maximum_page_rules() %>). Please remove one before adding another.
You've reached the maximum number of pages you can block ({Shields.maximum_page_rules()}). Please remove one before adding another.
</p>
</.notice>
@ -79,7 +77,7 @@ defmodule PlausibleWeb.Live.Shields.PageRules do
class="mr-4 cursor-help text-ellipsis truncate max-w-xs"
title={"Added at #{format_added_at(rule.inserted_at, @site.timezone)} by #{rule.added_by}"}
>
<%= rule.page_path %>
{rule.page_path}
</span>
</.td>
<.td hide_on_mobile>
@ -132,7 +130,7 @@ defmodule PlausibleWeb.Live.Shields.PageRules do
creatable
/>
<%= error_tag(f, :page_path) %>
<.error :for={msg <- f[:page_path].errors}>{translate_error(msg)}</.error>
<p class="mt-4 text-sm text-gray-500 dark:text-gray-400">
You can use a wildcard (<code>*</code>) to match multiple pages. For example,

View File

@ -100,7 +100,7 @@ defmodule PlausibleWeb.Live.Sites do
page_number={@sites.page_number}
total_pages={@sites.total_pages}
>
Total of <span class="font-medium"><%= @sites.total_entries %></span> sites
Total of <span class="font-medium">{@sites.total_entries}</span> sites
</.pagination>
<.invitation_modal :if={Enum.any?(@sites.entries, &(&1.entry_type == "invitation"))} />
</div>
@ -166,7 +166,7 @@ defmodule PlausibleWeb.Live.Sites do
/>
<div class="flex-1 truncate -mt-px">
<h3 class="text-gray-900 font-medium text-lg truncate dark:text-gray-100">
<%= @site.domain %>
{@site.domain}
</h3>
</div>
@ -212,7 +212,7 @@ defmodule PlausibleWeb.Live.Sites do
class="text-gray-900 font-medium text-lg truncate dark:text-gray-100"
style="width: calc(100% - 4rem)"
>
<%= @site.domain %>
{@site.domain}
</h3>
</div>
</div>
@ -308,7 +308,7 @@ defmodule PlausibleWeb.Live.Sites do
<div class="flex justify-between items-center">
<p>
<span class="text-gray-800 dark:text-gray-200">
<b><%= PlausibleWeb.StatsView.large_number_format(@hourly_stats.visitors) %></b>
<b>{PlausibleWeb.StatsView.large_number_format(@hourly_stats.visitors)}</b>
visitor<span :if={@hourly_stats.visitors != 1}>s</span> in last 24h
</span>
</p>
@ -357,7 +357,7 @@ defmodule PlausibleWeb.Live.Sites do
</path>
</svg>
<%= abs(@change) %>%
{abs(@change)}%
</p>
"""
end

View File

@ -2,6 +2,7 @@ defmodule PlausibleWeb.Router do
use PlausibleWeb, :router
use Plausible
import Phoenix.LiveView.Router
import PhoenixStorybook.Router
pipeline :browser do
plug :accepts, ["html"]
@ -77,6 +78,15 @@ defmodule PlausibleWeb.Router do
forward "/sent-emails", Bamboo.SentEmailViewerPlug
end
scope "/" do
storybook_assets()
end
scope "/", PlausibleWeb do
pipe_through :browser
live_storybook("/storybook", backend_module: PlausibleWeb.Storybook)
end
on_ee do
use Kaffy.Routes,
scope: "/crm",

View File

@ -0,0 +1,13 @@
defmodule PlausibleWeb.Storybook do
@moduledoc false
use PhoenixStorybook,
otp_app: :plausible_web,
title: "Plausible Storybook",
content_path: Path.expand("../../storybook", __DIR__),
# assets path are remote path, not local file-system paths
css_path: "/css/storybook.css",
js_path: "/js/storybook.js",
sandbox_class: "plausible",
color_mode: true
end

View File

@ -18,13 +18,13 @@
<:subtitle :if={@has_email_code?}>
<p class="truncate">
Please enter the 4-digit code we sent to <b><%= @conn.assigns[:current_user].email %></b>
Please enter the 4-digit code we sent to <b>{@conn.assigns[:current_user].email}</b>
</p>
</:subtitle>
<:subtitle :if={!@has_email_code?}>
<p class="truncate">
A 4-digit activation code will be sent to <b><%= @conn.assigns[:current_user].email %></b>
A 4-digit activation code will be sent to <b>{@conn.assigns[:current_user].email}</b>
</p>
</:subtitle>
@ -46,7 +46,7 @@
</.form>
</div>
<%= error_tag(assigns, :error) %>
<.error>{@error}</.error>
<div :if={!@has_email_code?}>
<.button_link method="post" class="w-full" href="/activate/request-code">
@ -65,7 +65,7 @@
<.styled_link href="/activate/request-code" method="post">
Send a new code
</.styled_link>
to <%= @conn.assigns[:current_user].email %>
to {@conn.assigns[:current_user].email}
</:item>
<:item :if={ee?()}>
<.styled_link href="https://plausible.io/contact" new_tab={true}>
@ -88,7 +88,7 @@
<.styled_link method="post" href={Routes.settings_path(@conn, :cancel_update_email)}>
Change email back to
</.styled_link>
<%= @conn.assigns[:current_user].previous_email %>
{@conn.assigns[:current_user].previous_email}
</:item>
<:item :if={not @has_any_memberships?}>

View File

@ -16,7 +16,7 @@
class="font-mono border-2 border-dotted border-gray-200 dark:border-gray-700 rounded-md text-gray-600 dark:text-gray-200 text-lg bg-gray-100 dark:bg-gray-900 p-2 mt-6 flex flex-wrap"
>
<%= for code <- @recovery_codes do %>
<div class="basis-1/2 text-center"><%= code %></div>
<div class="basis-1/2 text-center">{code}</div>
<% end %>
</div>

View File

@ -1,11 +1,11 @@
<.focus_box>
<:title>
<%= Phoenix.Flash.get(@flash, :login_title) || "Enter your account credentials" %>
{Phoenix.Flash.get(@flash, :login_title) || "Enter your account credentials"}
</:title>
<:subtitle>
<%= if Phoenix.Flash.get(@flash, :login_instructions) do %>
<p class="text-gray-500 mt-1 mb-2">
<%= Phoenix.Flash.get(@flash, :login_instructions) %>
{Phoenix.Flash.get(@flash, :login_instructions)}
</p>
<% end %>
</:subtitle>
@ -30,7 +30,7 @@
</div>
<%= if @conn.assigns[:error] do %>
<div class="text-red-500 mt-4"><%= @conn.assigns[:error] %></div>
<div class="text-red-500 mt-4">{@conn.assigns[:error]}</div>
<% end %>
<.button class="w-full" type="submit">Log in</.button>

View File

@ -1,4 +1,4 @@
<%= live_render(@conn, PlausibleWeb.Live.ResetPasswordForm,
{live_render(@conn, PlausibleWeb.Live.ResetPasswordForm,
container: {:div, class: "contents"},
session: %{"email" => @email}
) %>
)}

View File

@ -12,14 +12,14 @@
<.input type="email" field={f[:email]} placeholder="user@example.com" />
</div>
<%= if @conn.assigns[:error] do %>
<div class="text-red-500 my-2"><%= @conn.assigns[:error] %></div>
<div class="text-red-500 my-2">{@conn.assigns[:error]}</div>
<% end %>
<%= if PlausibleWeb.Captcha.enabled?() do %>
<div class="mt-4">
<div class="h-captcha" data-sitekey={PlausibleWeb.Captcha.sitekey()}></div>
<%= if assigns[:captcha_error] do %>
<div class="text-red-500 text-xs mt-3"><%= @captcha_error %></div>
<div class="text-red-500 text-xs mt-3">{@captcha_error}</div>
<% end %>
<script src="https://hcaptcha.com/1/api.js" async defer>
</script>

View File

@ -1,7 +1,7 @@
<div class="bg-white dark:bg-gray-800 max-w-md w-full mx-auto shadow-md rounded px-8 pt-6 pb-8 mb-4 mt-8">
<h2 class="text-xl font-black dark:text-gray-100">Success!</h2>
<div class="my-4 leading-tight dark:text-gray-100">
We've sent an email containing password reset instructions to <b><%= @email %></b>
We've sent an email containing password reset instructions to <b>{@email}</b>
if it's registered in our system.
</div>
<div class="mt-8 text-sm dark:text-gray-100">

View File

@ -25,12 +25,12 @@
<tbody class="bg-white dark:bg-gray-800">
<tr class="border-b border-gray-200">
<td class="px-6 py-4 text-sm leading-5 font-bold dark:text-gray-100">
<%= present_currency(@preview_info["immediate_payment"]["currency"]) %><%= @preview_info[
{present_currency(@preview_info["immediate_payment"]["currency"])}{@preview_info[
"immediate_payment"
]["amount"] %>
]["amount"]}
</td>
<td class="px-6 py-4 text-sm leading-5 dark:text-gray-100">
<%= present_date(@preview_info["immediate_payment"]["date"]) %>
{present_date(@preview_info["immediate_payment"]["date"])}
</td>
</tr>
</tbody>
@ -60,12 +60,12 @@
<tbody class="bg-white dark:bg-gray-800">
<tr class="border-b border-gray-200">
<td class="px-6 py-4 text-sm leading-5 font-bold dark:text-gray-100">
<%= present_currency(@preview_info["immediate_payment"]["currency"]) %><%= @preview_info[
{present_currency(@preview_info["immediate_payment"]["currency"])}{@preview_info[
"next_payment"
]["amount"] %>
]["amount"]}
</td>
<td class="px-6 py-4 text-sm leading-5 dark:text-gray-100">
<%= present_date(@preview_info["next_payment"]["date"]) %>
{present_date(@preview_info["next_payment"]["date"])}
</td>
</tr>
</tbody>

View File

@ -1,4 +1,4 @@
<%= live_render(@conn, PlausibleWeb.Live.ChoosePlan,
{live_render(@conn, PlausibleWeb.Live.ChoosePlan,
id: "choose-plan",
session: %{"remote_ip" => PlausibleWeb.RemoteIP.get(@conn)}
) %>
)}

View File

@ -1,19 +1,19 @@
<div class="mx-auto mt-6 text-center">
<h1 class="text-3xl font-black text-black dark:text-gray-100">
<%= if @subscription_resumable,
{if @subscription_resumable,
do: "Change subscription plan",
else: "Upgrade to Enterprise" %>
else: "Upgrade to Enterprise"}
</h1>
</div>
<div class="w-full max-w-lg px-4 mx-auto mt-4 text-gray-900 dark:text-gray-100">
<div class="flex-1 p-8 mt-8 rounded bg-white shadow-md dark:bg-gray-800 dark:shadow-none">
<div class="w-full pb-4">
<span>
<%= if @subscription_resumable,
{if @subscription_resumable,
do:
"We've prepared your account for an upgrade to custom limits outside the listed plans:",
else:
"We've prepared a custom enterprise plan for your account with the following limits:" %>
"We've prepared a custom enterprise plan for your account with the following limits:"}
</span>
</div>
<PlausibleWeb.Components.Billing.present_enterprise_plan plan={@latest_enterprise_plan} />
@ -21,19 +21,19 @@
<span>
The plan is priced at
<b>
<%= case @price do
{case @price do
%Money{} = money -> Plausible.Billing.format_price(money)
nil -> "N/A"
end %>
end}
</b>
</span>
<span>
per <%= if @latest_enterprise_plan.billing_interval == :yearly,
per {if @latest_enterprise_plan.billing_interval == :yearly,
do: "year",
else: "month" %> + VAT if applicable. <%= if @subscription_resumable,
else: "month"} + VAT if applicable. {if @subscription_resumable,
do:
"On the next page, our payment provider will calculate the prorated amount that your card will be charged if you decide to upgrade now.",
else: "Click the button below to upgrade." %>
else: "Click the button below to upgrade."}
</span>
</ul>
<div class="w-max">

View File

@ -3,9 +3,9 @@
<%= for log <- @queries do %>
<details class="group py-1">
<summary class="flex cursor-pointer flex-row items-center justify-between py-1 font-semibold text-gray-800 dark:text-gray-200 pt-4">
<%= log["request_method"] %> <%= controller_name(log["phoenix_controller"]) %>.<%= log[
{log["request_method"]} {controller_name(log["phoenix_controller"])}.{log[
"phoenix_action"
] %> (<%= log[:query_duration_ms] %>ms)
]} ({log[:query_duration_ms]}ms)
<svg
class="h-6 w-6 rotate-0 transform text-gray-400 dark:text-gray-200 group-open:rotate-180"
xmlns="http://www.w3.org/2000/svg"
@ -22,7 +22,7 @@
<tbody>
<%= for {key, value} <- log do %>
<tr class="table-row">
<td class="table-cell p-2"><%= key %></td>
<td class="table-cell p-2">{key}</td>
<td class="table-cell p-2">
<%= case key do %>
<% :query -> %>
@ -30,7 +30,7 @@
<% "params" -> %>
<pre><%= Jason.encode!(value, pretty: true) %></pre>
<% _ -> %>
<%= value %>
{value}
<% end %>
</td>
</tr>

View File

@ -1 +1 @@
Enter <%= @code %> to verify your email address. This code will expire in 4 hours.
Enter {@code} to verify your email address. This code will expire in 4 hours.

View File

@ -1,6 +1,6 @@
You used to have an active account with <%= Plausible.product_name() %>, a simple, lightweight, open source and privacy-first Google Analytics alternative.
You used to have an active account with {Plausible.product_name()}, a simple, lightweight, open source and privacy-first Google Analytics alternative.
<br /><br />
We've noticed that you're still sending us stats so we're writing to inform you that we'll stop accepting stats from your sites <%= @time %>. We're an independent, bootstrapped service and we don't sell your data, so this will reduce our server costs and help keep us sustainable.
We've noticed that you're still sending us stats so we're writing to inform you that we'll stop accepting stats from your sites {@time}. We're an independent, bootstrapped service and we don't sell your data, so this will reduce our server costs and help keep us sustainable.
<br /><br /> If you'd like to continue counting your site stats in a privacy-friendly way, please
<a href={plausible_url()}>login to your Plausible account</a> and start a subscription.
<br /><br />

View File

@ -2,8 +2,7 @@ You've activated
<%= if Plausible.ee?() do %>
your free 30-day trial of
<% end %>
<%= Plausible.product_name() %>, a simple and privacy-friendly website analytics tool.
<br /><br />
{Plausible.product_name()}, a simple and privacy-friendly website analytics tool. <br /><br />
<a href={"#{plausible_url()}/sites/new"}>Click here</a>
to add your website URL, your timezone and install our one-line JavaScript snippet to start collecting visitor statistics.
<%= if Plausible.ee?() do %>

View File

@ -1,12 +1,12 @@
<%= if @success do %>
Your CSV import has completed successfully. The Plausible dashboard for <%= @site_import.site.domain %> now contains historical imported data from <%= date_format(
Your CSV import has completed successfully. The Plausible dashboard for {@site_import.site.domain} now contains historical imported data from {date_format(
@site_import.start_date
) %> to <%= date_format(@site_import.end_date) %>
)} to {date_format(@site_import.end_date)}
<br /><br />
<a href={@link}>Click here</a>
to view your dashboard.
<% else %>
Unfortunately, your CSV import for <%= @site_import.site.domain %> did not complete successfully. Sorry about that!
Unfortunately, your CSV import for {@site_import.site.domain} did not complete successfully. Sorry about that!
<br /><br /> Please try to do the import once again.
<%= if ee?() do %>
<br /> <br />

View File

@ -1,18 +1,18 @@
Last week we sent a reminder that your site traffic has exceeded the limits of your <%= Plausible.product_name() %> subscription tier for two consecutive months. Since we haven't received a response, we've had to temporarily lock access to your stats.
Last week we sent a reminder that your site traffic has exceeded the limits of your {Plausible.product_name()} subscription tier for two consecutive months. Since we haven't received a response, we've had to temporarily lock access to your stats.
<br /><br />
Your subscription is still active, we're still counting your stats and haven't deleted any of your data but as you have outgrown your subscription tier, we kindly ask you to upgrade to match your new traffic levels. Upon upgrading to a suitable tier, your dashboard access will be immediately restored.
<br /><br />
During the last billing cycle (<%= PlausibleWeb.TextHelpers.format_date_range(
During the last billing cycle ({PlausibleWeb.TextHelpers.format_date_range(
@usage.last_cycle.date_range
) %>), your account recorded <%= PlausibleWeb.AuthView.delimit_integer(@usage.last_cycle.total) %> billable pageviews. In the billing cycle before that (<%= PlausibleWeb.TextHelpers.format_date_range(
)}), your account recorded {PlausibleWeb.AuthView.delimit_integer(@usage.last_cycle.total)} billable pageviews. In the billing cycle before that ({PlausibleWeb.TextHelpers.format_date_range(
@usage.penultimate_cycle.date_range
) %>), the usage was <%= PlausibleWeb.AuthView.delimit_integer(@usage.penultimate_cycle.total) %> billable pageviews. Note that billable pageviews include both standard pageviews and custom events. In your
)}), the usage was {PlausibleWeb.AuthView.delimit_integer(@usage.penultimate_cycle.total)} billable pageviews. Note that billable pageviews include both standard pageviews and custom events. In your
<a href={PlausibleWeb.Router.Helpers.settings_url(PlausibleWeb.Endpoint, :subscription)}>account settings</a>, you'll find an overview of your usage and limits.
<br /><br />
<%= if @suggested_plan == :enterprise do %>
Your usage exceeds our standard plans, so please reply back to this email for a tailored quote.
<% else %>
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan)}>Click here to upgrade your subscription</a>. We recommend you upgrade to the <%= @suggested_plan.volume %>/mo plan. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire.
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan)}>Click here to upgrade your subscription</a>. We recommend you upgrade to the {@suggested_plan.volume}/mo plan. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire.
<br /><br />
If your usage decreases in the future, you can switch to a lower plan at any time. Any credit balance will automatically apply to future payments.
<% end %>

View File

@ -1,7 +1,7 @@
We've recorded <%= @current_visitors %> visitors on
We've recorded {@current_visitors} visitors on
<a href={"https://" <> @site.domain}><%= @site.domain %></a> in the last 12 hours.
<%= if @dashboard_link do %>
<br /><br /> View dashboard: <a href={@dashboard_link}><%= @dashboard_link %></a>
<br /><br /> View dashboard: <a href={@dashboard_link}>{@dashboard_link}</a>
<br /><br /> Something looks off? Please
<a href={@installation_link}>review your installation</a>
to verify that Plausible has been integrated correctly.

View File

@ -1,15 +1,14 @@
Automated notice about an enterprise account that has gone over their limits. <br /><br />
Customer email: <%= @user.email %><br />
Last billing cycle: <%= PlausibleWeb.TextHelpers.format_date_range(
Customer email: {@user.email}<br />
Last billing cycle: {PlausibleWeb.TextHelpers.format_date_range(
@pageview_usage.last_cycle.date_range
) %><br />
Last cycle pageview usage: <%= PlausibleWeb.AuthView.delimit_integer(
)}<br />
Last cycle pageview usage: {PlausibleWeb.AuthView.delimit_integer(
@pageview_usage.last_cycle.total
) %> billable pageviews<br />
Penultimate billing cycle: <%= PlausibleWeb.TextHelpers.format_date_range(
)} billable pageviews<br />
Penultimate billing cycle: {PlausibleWeb.TextHelpers.format_date_range(
@pageview_usage.penultimate_cycle.date_range
) %><br />
Penultimate cycle pageview usage: <%= PlausibleWeb.AuthView.delimit_integer(
)}<br />
Penultimate cycle pageview usage: {PlausibleWeb.AuthView.delimit_integer(
@pageview_usage.penultimate_cycle.total
) %> billable pageviews<br />
Site usage: <%= @site_usage %> / <%= @site_allowance %> allowed sites<br />
)} billable pageviews<br /> Site usage: {@site_usage} / {@site_allowance} allowed sites<br />

View File

@ -1,7 +1,7 @@
<h1>Error report</h1>
<p>
Reported by: <%= @reported_by %>
<br /> Sentry trace: <a href={sentry_link(@trace_id)}><%= @trace_id %></a>
Reported by: {@reported_by}
<br /> Sentry trace: <a href={sentry_link(@trace_id)}>{@trace_id}</a>
<br />
</p>
<h2>User feedback:</h2>

View File

@ -1,3 +1,3 @@
<%= @inviter.email %> has invited you to the <%= @site.domain %> site on <%= Plausible.product_name() %>.
{@inviter.email} has invited you to the {@site.domain} site on {Plausible.product_name()}.
<a href={Routes.site_url(PlausibleWeb.Endpoint, :index)}>Click here</a> to view and respond to the invitation. The invitation
will expire 48 hours after this email is sent.

View File

@ -1,3 +1,3 @@
<%= @inviter.email %> has invited you to the "<%= @team.name %>" team on <%= Plausible.product_name() %>.
{@inviter.email} has invited you to the "{@team.name}" team on {Plausible.product_name()}.
<a href={Routes.site_url(PlausibleWeb.Endpoint, :index)}>Click here</a> to view and respond to the invitation. The invitation
will expire 48 hours after this email is sent.

View File

@ -1,4 +1,4 @@
Your <%= Plausible.product_name() %> export for <%= @site.domain %> has encountered an error and was unsuccessful.
Your {Plausible.product_name()} export for {@site.domain} has encountered an error and was unsuccessful.
Sorry for the trouble this may have caused. <br /><br /> Please attempt to export your data again.
<%= if ee?() do %>
Should the problem persist, do reply to this email so we can assist. Thanks!

View File

@ -1,6 +1,6 @@
Your <%= Plausible.product_name() %> export for <%= @site.domain %> is now ready for download.
Your {Plausible.product_name()} export for {@site.domain} is now ready for download.
Please click <a href={@download_url}>here</a>
to start the download process.
<%= if @expires_in do %>
Note that this link will expire <%= @expires_in %>.
Note that this link will expire {@expires_in}.
<% end %>

View File

@ -1,12 +1,12 @@
<%= if @success do %>
Your Google Analytics import has completed successfully. The Plausible dashboard for <%= @site_import.site.domain %> now contains historical imported data from <%= date_format(
Your Google Analytics import has completed successfully. The Plausible dashboard for {@site_import.site.domain} now contains historical imported data from {date_format(
@site_import.start_date
) %> to <%= date_format(@site_import.end_date) %>
)} to {date_format(@site_import.end_date)}
<br /><br />
<a href={@link}>Click here</a>
to view your dashboard.
<% else %>
Unfortunately, your Google Analytics import for <%= @site_import.site.domain %> did not complete successfully. Sorry about that!
Unfortunately, your Google Analytics import for {@site_import.site.domain} did not complete successfully. Sorry about that!
<br /><br />
Please try to do the import once again. Sometimes the Google Analytics API just randomly returns empty data. It's intermittent and random. Trying to do the import again may return what you need.
<%= if ee?() do %>

View File

@ -1,2 +1,2 @@
<%= @invitee_email %> has accepted your invitation to <%= @site.domain %>.
{@invitee_email} has accepted your invitation to {@site.domain}.
<a href={Routes.site_url(PlausibleWeb.Endpoint, :settings_general, @site.domain)}>Click here</a> to view site settings.

View File

@ -1,2 +1,2 @@
<%= @guest_invitation.team_invitation.email %> has rejected your invitation to <%= @guest_invitation.site.domain %>.
{@guest_invitation.team_invitation.email} has rejected your invitation to {@guest_invitation.site.domain}.
<a href={Routes.site_url(PlausibleWeb.Endpoint, :settings_general, @guest_invitation.site.domain)}>Click here</a> to view site settings.

View File

@ -1,4 +1,4 @@
<%= @inviter.email %> has invited you to join the <%= @site.domain %> site on <%= Plausible.product_name() %>.
{@inviter.email} has invited you to join the {@site.domain} site on {Plausible.product_name()}.
<a href={
Routes.auth_url(
PlausibleWeb.Endpoint,

View File

@ -1,4 +1,4 @@
<%= @inviter.email %> has invited you to join the "<%= @team.name %>" team on <%= Plausible.product_name() %>.
{@inviter.email} has invited you to join the "{@team.name}" team on {Plausible.product_name()}.
<a href={
Routes.auth_url(
PlausibleWeb.Endpoint,

View File

@ -1,19 +1,19 @@
Thanks for being a <%= Plausible.product_name() %> subscriber! <br /><br />
Thanks for being a {Plausible.product_name()} subscriber! <br /><br />
This is a friendly reminder that your traffic has exceeded your subscription tier for two consecutive months. Congrats on all that traffic!
<br /><br />
To maintain uninterrupted access to your stats, we kindly ask you to upgrade your account to match your new traffic levels. Please note, if your account isn't upgraded within the next 7 days, access to your stats will be temporarily locked.
<br /><br />
During the last billing cycle (<%= PlausibleWeb.TextHelpers.format_date_range(
During the last billing cycle ({PlausibleWeb.TextHelpers.format_date_range(
@usage.last_cycle.date_range
) %>), your account recorded <%= PlausibleWeb.AuthView.delimit_integer(@usage.last_cycle.total) %> billable pageviews. In the billing cycle before that (<%= PlausibleWeb.TextHelpers.format_date_range(
)}), your account recorded {PlausibleWeb.AuthView.delimit_integer(@usage.last_cycle.total)} billable pageviews. In the billing cycle before that ({PlausibleWeb.TextHelpers.format_date_range(
@usage.penultimate_cycle.date_range
) %>), your account used <%= PlausibleWeb.AuthView.delimit_integer(@usage.penultimate_cycle.total) %> billable pageviews. Note that billable pageviews include both standard pageviews and custom events. In your
)}), your account used {PlausibleWeb.AuthView.delimit_integer(@usage.penultimate_cycle.total)} billable pageviews. Note that billable pageviews include both standard pageviews and custom events. In your
<a href={plausible_url() <> PlausibleWeb.Router.Helpers.settings_path(PlausibleWeb.Endpoint, :subscription)}>account settings</a>, you'll find an overview of your usage and limits.
<br /><br />
<%= if @suggested_plan == :enterprise do %>
Your usage exceeds our standard plans, so please reply back to this email for a tailored quote.
<% else %>
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan)}>Click here to upgrade your subscription</a>. We recommend you upgrade to the <%= @suggested_plan.volume %>/mo plan. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire.
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan)}>Click here to upgrade your subscription</a>. We recommend you upgrade to the {@suggested_plan.volume}/mo plan. The new charge will be prorated to reflect the amount you have already paid and the time until your current subscription is supposed to expire.
<br /><br />
If your usage decreases in the future, you can switch to a lower plan at any time. Any credit balance will automatically apply to future payments.
<% end %>

View File

@ -1,3 +1,3 @@
<%= @new_owner_email %> has accepted the ownership transfer of <%= @site.domain %>. They will be responsible for billing of it going
{@new_owner_email} has accepted the ownership transfer of {@site.domain}. They will be responsible for billing of it going
forward and your role has been changed to <b>admin</b>.
<a href={Routes.site_url(PlausibleWeb.Endpoint, :settings_general, @site.domain)}>Click here</a> to view site settings.

View File

@ -1,2 +1,2 @@
<%= @site_transfer.email %> has rejected the ownership transfer of <%= @site_transfer.site.domain %>.
{@site_transfer.email} has rejected the ownership transfer of {@site_transfer.site.domain}.
<a href={Routes.site_url(PlausibleWeb.Endpoint, :settings_general, @site_transfer.site.domain)}>Click here</a> to view site settings.

View File

@ -1,4 +1,4 @@
<%= @inviter.email %> has requested to transfer the ownership of <%= @site.domain %> site on <%= Plausible.product_name() %> to you.
{@inviter.email} has requested to transfer the ownership of {@site.domain} site on {Plausible.product_name()} to you.
<%= if @new_owner_account do %>
<a href={Routes.site_url(PlausibleWeb.Endpoint, :index)}>Click here</a>
to view and respond to the invitation.

View File

@ -1,4 +1,4 @@
An administrator of <%= @guest_membership.site.domain %> has removed you as a member. You won't be able to see the stats anymore.
An administrator of {@guest_membership.site.domain} has removed you as a member. You won't be able to see the stats anymore.
<br /><br />
<a href={Routes.site_url(PlausibleWeb.Endpoint, :index)}>Click here</a>
to view your sites.

View File

@ -2,7 +2,7 @@
You signed up for a free 30-day trial of Plausible, a simple and privacy-friendly website analytics tool.
<br /><br />
<% end %>
To finish your setup for <%= @site.domain %>, review
To finish your setup for {@site.domain}, review
<a href={"#{plausible_url()}/#{URI.encode_www_form(@site.domain)}/installation"}>your installation</a> and start collecting visitor statistics.
<br /><br />
This Plausible script is 45 times smaller than Google Analytics script so youll have a fast loading site while getting all the important traffic insights on one single page.

View File

@ -1,15 +1,15 @@
There are currently <%= @current_visitors %> visitors on
There are currently {@current_visitors} visitors on
<a href={"https://" <> @site.domain}><%= @site.domain %></a>.
<%= if Enum.count(@sources) > 0 do %>
<br />
<br /> The top sources for current visitors:<br />
<%= for %{name: source, count: visitors} <- @sources do %>
<%= source %> - <%= visitors %> visitor<%= if visitors > 1, do: "s" %><br />
{source} - {visitors} visitor{if visitors > 1, do: "s"}<br />
<% end %>
<% end %>
<%= if @link do %>
<br /><br /> View dashboard: <a href={@link}><%= @link %></a>
<br /><br /> View dashboard: <a href={@link}>{@link}</a>
<% end %>
<br /><br /> Congrats on the spike in traffic!
<%= if Plausible.ce? do %>

View File

@ -1,2 +1,2 @@
<%= @invitee_email %> has accepted your invitation to "<%= @team.name %>" team.
{@invitee_email} has accepted your invitation to "{@team.name}" team.
<a href={Routes.settings_url(PlausibleWeb.Endpoint, :team_general)}>Click here</a> to view team settings.

View File

@ -1,2 +1,2 @@
<%= @team_invitation.email %> has rejected your invitation to \"<%= @team_invitation.team.name %>\" team.
{@team_invitation.email} has rejected your invitation to \"{@team_invitation.team.name}\" team.
<a href={Routes.settings_url(PlausibleWeb.Endpoint, :team_general)}>Click here</a> to view team settings.

View File

@ -4,5 +4,4 @@ Your free Plausible trial has now expired. Upgrade your account to continue rece
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan)}>
Upgrade now
</a>
<br /><br />
We will keep recording stats for <%= @extra_offset %> days to give you time to upgrade.
<br /><br /> We will keep recording stats for {@extra_offset} days to give you time to upgrade.

View File

@ -1,15 +1,15 @@
Thanks for exploring Plausible, a simple and privacy-friendly alternative to Google Analytics. Your free 30-day trial is ending <%= @day %>, but you can keep using Plausible by upgrading to a paid plan.
Thanks for exploring Plausible, a simple and privacy-friendly alternative to Google Analytics. Your free 30-day trial is ending {@day}, but you can keep using Plausible by upgrading to a paid plan.
<br /><br />
In the last month, your account has used <%= PlausibleWeb.AuthView.delimit_integer(@usage) %> billable pageviews<%= if @custom_events >
0,
do:
" and custom events in total",
else:
"" %>.
In the last month, your account has used {PlausibleWeb.AuthView.delimit_integer(@usage)} billable pageviews{if @custom_events >
0,
do:
" and custom events in total",
else:
""}.
<%= if @suggested_plan == :enterprise do %>
This is more than our standard plans, so please reply back to this email to get a quote for your volume.
<% else %>
Based on that we recommend you select a <%= @suggested_plan.volume %>/mo plan. <br /><br />
Based on that we recommend you select a {@suggested_plan.volume}/mo plan. <br /><br />
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan)}>
Upgrade now
</a>

View File

@ -1,7 +1,7 @@
Time flies! This is a reminder that your annual subscription for <%= Plausible.product_name() %> will expire on <%= @next_bill_date %>.
Time flies! This is a reminder that your annual subscription for {Plausible.product_name()} will expire on {@next_bill_date}.
<br /><br /> You need to
<a href={PlausibleWeb.Router.Helpers.billing_url(PlausibleWeb.Endpoint, :choose_plan)}>renew your subscription</a> if you want to continue using Plausible to count your website stats in a privacy-friendly way.
<br /><br />
If you don't want to continue your subscription, there's no action required. You will lose access to your dashboard on <%= @next_bill_date %> and we'll stop accepting stats on <%= @accept_traffic_until %>.
If you don't want to continue your subscription, there's no action required. You will lose access to your dashboard on {@next_bill_date} and we'll stop accepting stats on {@accept_traffic_until}.
<br /><br />
Have a question, feedback or need some guidance? Just reply to this email to get in touch!

View File

@ -1,6 +1,6 @@
Time flies! This is a reminder that your annual subscription for <%= Plausible.product_name() %> is due to renew on <%= @date %>. We will automatically charge <%= PlausibleWeb.BillingView.present_currency(
Time flies! This is a reminder that your annual subscription for {Plausible.product_name()} is due to renew on {@date}. We will automatically charge {PlausibleWeb.BillingView.present_currency(
@currency
) %><%= @next_bill_amount %> from your preferred billing method. <br /><br />
)}{@next_bill_amount} from your preferred billing method. <br /><br />
There's no action required if you're happy to continue using Plausible to count your website stats in a privacy-friendly way.
<br /><br /> If you don't want to continue your subscription, you can cancel it on your
<a href={"#{plausible_url()}/settings"}>account settings page</a>. <br /><br />

View File

@ -1,5 +1,5 @@
<div class="container flex flex-col items-center text-center mt-24">
<h1 class="text-5xl font-black dark:text-gray-100"><%= @status %></h1>
<h1 class="text-5xl font-black dark:text-gray-100">{@status}</h1>
<div class="mt-4 text-xl dark:text-gray-100">Oops! There's nothing here</div>
<div class="text-xl dark:text-gray-100">
Trying to access your dashboard? You may need to log in again to see it

View File

@ -1,5 +1,5 @@
<div class="container text-center mt-24">
<h1 class="text-5xl font-black dark:text-gray-100"><%= @status %></h1>
<div class="my-4 text-xl dark:text-gray-100"><%= @message %></div>
<h1 class="text-5xl font-black dark:text-gray-100">{@status}</h1>
<div class="my-4 text-xl dark:text-gray-100">{@message}</div>
<.button_link href={PlausibleWeb.LayoutView.home_dest(@conn)}>Go to homepage</.button_link>
</div>

View File

@ -19,7 +19,7 @@
<div class="mt-6">
<.label for={f[:property].id}>Google Analytics property</.label>
<span class="block w-full text-base dark:text-gray-100 sm:text-sm dark:bg-gray-800">
<%= @selected_property_name %>
{@selected_property_name}
</span>
<.input type="hidden" value={@selected_property} field={f[:property]} readonly="true" />
</div>
@ -27,7 +27,7 @@
<div class="w-36">
<.label for={f[:start_date].id}>From</.label>
<span class="block w-full text-base dark:text-gray-100 sm:text-sm dark:bg-gray-800">
<%= PlausibleWeb.EmailView.date_format(@start_date) %>
{PlausibleWeb.EmailView.date_format(@start_date)}
</span>
<.input type="hidden" value={@start_date} field={f[:start_date]} readonly="true" />
</div>
@ -35,7 +35,7 @@
<div class="w-36">
<.label for={f[:end_date].id}>To</.label>
<span class="block w-full text-base dark:text-gray-100 sm:text-sm dark:bg-gray-800">
<%= PlausibleWeb.EmailView.date_format(@end_date) %>
{PlausibleWeb.EmailView.date_format(@end_date)}
</span>
<.input type="hidden" value={@end_date} field={f[:end_date]} readonly="true" />
</div>

View File

@ -4,7 +4,7 @@
</:title>
<:subtitle>
Choose the property in your Google Analytics account that will be imported to the <%= @site.domain %> dashboard.
Choose the property in your Google Analytics account that will be imported to the {@site.domain} dashboard.
</:subtitle>
<.form
:let={f}
@ -27,7 +27,7 @@
/>
<p class="text-red-600 dark:text-red-700">
<%= @conn.assigns[:selected_property_error] %>
{@conn.assigns[:selected_property_error]}
</p>
</div>

View File

@ -33,10 +33,10 @@
</div>
<div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">
<%= Phoenix.Flash.get(@flash, :success_title) || "Success!" %>
{Phoenix.Flash.get(@flash, :success_title) || "Success!"}
</p>
<p class="mt-1 text-sm leading-5 text-gray-500 dark:text-gray-200">
<%= Phoenix.Flash.get(@flash, :success) %>
{Phoenix.Flash.get(@flash, :success)}
</p>
</div>
<div class="ml-4 flex-shrink-0 flex">
@ -102,10 +102,10 @@
</div>
<div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">
<%= Phoenix.Flash.get(@flash, :error_title) || "Error" %>
{Phoenix.Flash.get(@flash, :error_title) || "Error"}
</p>
<p class="mt-1 text-sm leading-5 text-gray-500 dark:text-gray-200">
<%= Phoenix.Flash.get(@flash, :error) %>
{Phoenix.Flash.get(@flash, :error)}
</p>
</div>
<div class="ml-4 flex-shrink-0 flex">

Some files were not shown because too many files have changed in this diff Show More