diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000000..008680e95e --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,9 @@ +{ + "permissions": { + "allow": [ + "Bash(iex:*)" + ], + "deny": [], + "ask": [] + } +} diff --git a/assets/.claude/settings.local.json b/assets/.claude/settings.local.json new file mode 100644 index 0000000000..eac2820576 --- /dev/null +++ b/assets/.claude/settings.local.json @@ -0,0 +1,11 @@ +{ + "permissions": { + "allow": [ + "Bash(grep:*)", + "Read(//Users/ukutaht/plausible/analytics/lib/**)", + "Bash(node:*)" + ], + "deny": [], + "ask": [] + } +} diff --git a/assets/.stylelintrc.json b/assets/.stylelintrc.json index 799642a7b8..51fbcf990f 100644 --- a/assets/.stylelintrc.json +++ b/assets/.stylelintrc.json @@ -3,7 +3,7 @@ "ignoreFiles": ["./node_modules/**/*.*"], "rules": { "import-notation": "string", - "at-rule-no-unknown": [true, { "ignoreAtRules": ["apply", "screen"] }], + "at-rule-no-unknown": [true, { "ignoreAtRules": ["apply", "screen", "plugin", "source", "theme", "utility", "custom-variant"] }], "at-rule-empty-line-before": [ "always", { "except": ["blockless-after-same-name-blockless"], "ignoreAtRules": ["apply"] } diff --git a/assets/css/app.css b/assets/css/app.css index 9295bd0fee..75fa7e8272 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -1,15 +1,72 @@ -@import 'tailwindcss/base'; -@import 'flatpickr/dist/flatpickr.min.css'; -@import './modal.css'; -@import './loader.css'; -@import './tooltip.css'; -@import './flatpickr-colors.css'; -@import './chartjs.css'; -@import 'tailwindcss/components'; -@import 'tailwindcss/utilities'; +@import 'tailwindcss' source(none); +@import 'flatpickr/dist/flatpickr.min.css' layer(components); +@import './modal.css' layer(components); +@import './loader.css' layer(components); +@import './tooltip.css' layer(components); +@import './flatpickr-colors.css' layer(components); +@import './chartjs.css' layer(components); -[x-cloak] { - display: none; +@plugin "@tailwindcss/forms"; + +@source "../css"; +@source "../js"; +@source "../../lib/plausible_web"; +@source "../../extra/lib/plausible_web"; + +/* Tailwind v3 compatibility: restore v3 default border and ring styling */ + +@layer base { + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + border-color: var(--color-gray-200, currentColor); + } + + button:not(:disabled), + [role='button']:not(:disabled) { + cursor: pointer; + } +} + +@theme { + /* Color aliases from tailwind.config.js */ + + /* yellow: colors.amber - Map yellow to amber colors */ + --color-yellow-50: var(--color-amber-50); + --color-yellow-100: var(--color-amber-100); + --color-yellow-200: var(--color-amber-200); + --color-yellow-300: var(--color-amber-300); + --color-yellow-400: var(--color-amber-400); + --color-yellow-500: var(--color-amber-500); + --color-yellow-600: var(--color-amber-600); + --color-yellow-700: var(--color-amber-700); + --color-yellow-800: var(--color-amber-800); + --color-yellow-900: var(--color-amber-900); + --color-yellow-950: var(--color-amber-950); + + /* gray: colors.slate - Map gray to slate colors */ + --color-gray-50: var(--color-slate-50); + --color-gray-100: var(--color-slate-100); + --color-gray-200: var(--color-slate-200); + --color-gray-300: var(--color-slate-300); + --color-gray-400: var(--color-slate-400); + --color-gray-500: var(--color-slate-500); + --color-gray-600: var(--color-slate-600); + --color-gray-700: var(--color-slate-700); + --color-gray-800: var(--color-slate-800); + --color-gray-900: var(--color-slate-900); + + /* Custom gray shades from config (override some slate values) */ + --color-gray-150: rgb(234 238 244); + --color-gray-825: rgb(37 47 63); + --color-gray-850: rgb(26 32 44); + --color-gray-950: rgb(13 18 30); + + /* Set v3 default ring behavior */ + --default-ring-width: 3px; + --default-ring-color: var(--color-blue-500); } @media print { @@ -19,8 +76,22 @@ } } +@utility container { + margin-inline: auto; + padding-inline: 1rem; +} + +@custom-variant dark (&:where(.dark, .dark *)); +@custom-variant phx-click-loading (.phx-click-loading&, .phx-click-loading &); +@custom-variant phx-submit-loading (.phx-submit-loading&, .phx-submit-loading &); +@custom-variant phx-change-loading (.phx-change-loading&, .phx-change-loading &); + +[x-cloak] { + display: none; +} + .button { - @apply inline-flex justify-center px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent rounded-md leading-5 transition hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500; + @apply inline-flex justify-center px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent rounded-md leading-5 transition hover:bg-indigo-700 focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500; } .button[disabled] { @@ -58,7 +129,7 @@ blockquote { @apply px-4 py-2 my-4 border-l-4 border-gray-500; } -@screen xl { +@media (width >= 1280px) { .container { max-width: 70rem; } @@ -68,7 +139,7 @@ blockquote { height: 920px; } -@screen md { +@media (width >= 768px) { .pricing-table { height: auto; } diff --git a/assets/css/storybook.css b/assets/css/storybook.css index e78c04fc7d..2764e94fa3 100644 --- a/assets/css/storybook.css +++ b/assets/css/storybook.css @@ -1,10 +1,8 @@ -@import 'tailwindcss/base'; -@import 'tailwindcss/components'; -@import 'tailwindcss/utilities'; +@import 'tailwindcss' source(none); /* * Put your component styling within the Tailwind utilities layer. - * See the https://hexdocs.pm/phoenix_storybook/sandboxing.html guide for more info. +* See the https://hexdocs.pm/phoenix_storybook/sandboxing.html guide for more info. */ @layer utilities { diff --git a/assets/js/dashboard/components/combobox.js b/assets/js/dashboard/components/combobox.js index c414ad8c88..5c01c5a7c4 100644 --- a/assets/js/dashboard/components/combobox.js +++ b/assets/js/dashboard/components/combobox.js @@ -221,7 +221,7 @@ export default function PlausibleCombobox({ }, [isEmpty, singleOption, autoFocus]) const searchBoxClass = - 'border-none py-1 px-0 w-full inline-block rounded-md focus:outline-none focus:ring-0 text-sm' + 'border-none py-1 px-0 w-full inline-block rounded-md focus:outline-hidden focus:ring-0 text-sm' const containerClass = classNames('relative w-full', { [className]: !!className, @@ -264,7 +264,7 @@ export default function PlausibleCombobox({ return (