diff --git a/assets/css/app.css b/assets/css/app.css
index 378c8f90..38922297 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -1,5 +1,36 @@
-@import "tailwindcss/base";
-@import "tailwindcss/components";
-@import "tailwindcss/utilities";
+@variant phx-click-loading (.phx-click-loading&, .phx-click-loading &);
+@variant phx-submit-loading (.phx-submit-loading&, .phx-submit-loading &);
+@variant phx-change-loading (.phx-change-loading&, .phx-change-loading &);
-/* This file is for your main application CSS */
+@plugin "./heroicons.tailwind.plugin.js";
+@plugin "@tailwindcss/forms";
+
+@import "tailwindcss";
+
+@theme {
+ --color-brand: #d4af37;
+ --font-sans:
+ "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
+ "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ --animate-shake: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
+
+ @keyframes shake {
+ 10%,
+ 90% {
+ transform: translate3d(-1px, 0, 0);
+ }
+ 20%,
+ 80% {
+ transform: translate3d(2px, 0, 0);
+ }
+ 30%,
+ 50%,
+ 70% {
+ transform: translate3d(-4px, 0, 0);
+ }
+ 40%,
+ 60% {
+ transform: translate3d(4px, 0, 0);
+ }
+ }
+}
diff --git a/assets/css/heroicons.tailwind.plugin.js b/assets/css/heroicons.tailwind.plugin.js
new file mode 100644
index 00000000..95b2cbed
--- /dev/null
+++ b/assets/css/heroicons.tailwind.plugin.js
@@ -0,0 +1,47 @@
+const fs = require("fs");
+const path = require("path");
+
+module.exports = function ({ matchComponents, theme }) {
+ let iconsDir = path.join(process.cwd(), "deps/heroicons/optimized");
+ let values = {};
+ let icons = [
+ ["", "/24/outline"],
+ ["-solid", "/24/solid"],
+ ["-mini", "/20/solid"],
+ ["-micro", "/16/solid"],
+ ];
+ icons.forEach(([suffix, dir]) => {
+ fs.readdirSync(path.join(iconsDir, dir)).forEach((file) => {
+ let name = path.basename(file, ".svg") + suffix;
+ values[name] = { name, fullPath: path.join(iconsDir, dir, file) };
+ });
+ });
+ matchComponents(
+ {
+ hero: ({ name, fullPath }) => {
+ let content = fs
+ .readFileSync(fullPath)
+ .toString()
+ .replace(/\r?\n|\r/g, "");
+ let size = theme("spacing.6");
+ if (name.endsWith("-mini")) {
+ size = theme("spacing.5");
+ } else if (name.endsWith("-micro")) {
+ size = theme("spacing.4");
+ }
+ return {
+ [`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
+ "-webkit-mask": `var(--hero-${name})`,
+ mask: `var(--hero-${name})`,
+ "mask-repeat": "no-repeat",
+ "background-color": "currentColor",
+ "vertical-align": "middle",
+ display: "inline-block",
+ width: size,
+ height: size,
+ };
+ },
+ },
+ { values },
+ );
+};
diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js
deleted file mode 100644
index 880645a3..00000000
--- a/assets/tailwind.config.js
+++ /dev/null
@@ -1,98 +0,0 @@
-// See the Tailwind configuration guide for advanced usage
-// https://tailwindcss.com/docs/configuration
-
-const plugin = require("tailwindcss/plugin")
-const defaultTheme = require('tailwindcss/defaultTheme')
-const fs = require("fs")
-const path = require("path")
-
-module.exports = {
- content: [
- "./js/**/*.js",
- "../lib/music_library_web.ex",
- "../lib/music_library_web/**/*.*ex"
- ],
- theme: {
- extend: {
- colors: {
- brand: "#D4AF37",
- },
- fontFamily: {
- sans: ['Inter', ...defaultTheme.fontFamily.sans],
- },
- animation: {
- 'shake': 'shake 0.82s cubic-bezier(.36,.07,.19,.97) both',
- },
- keyframes: {
- 'shake': {
- '10%, 90%': {
- transform: 'translate3d(-1px, 0, 0)'
- },
- '20%, 80%': {
- transform: 'translate3d(2px, 0, 0)'
- },
- '30%, 50%, 70%': {
- transform: 'translate3d(-4px, 0, 0)'
- },
- '40%, 60%': {
- transform: 'translate3d(4px, 0, 0)'
- }
- }
- }
- },
- },
- plugins: [
- require("@tailwindcss/forms"),
- // Allows prefixing tailwind classes with LiveView classes to add rules
- // only when LiveView classes are applied, for example:
- //
- //
- //
- 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 &"])),
-
- // Embeds Heroicons (https://heroicons.com) into your app.css bundle
- // See your `CoreComponents.icon/1` for more information.
- //
- plugin(function ({ matchComponents, theme }) {
- let iconsDir = path.join(__dirname, "../deps/heroicons/optimized")
- let values = {}
- let icons = [
- ["", "/24/outline"],
- ["-solid", "/24/solid"],
- ["-mini", "/20/solid"],
- ["-micro", "/16/solid"]
- ]
- icons.forEach(([suffix, dir]) => {
- fs.readdirSync(path.join(iconsDir, dir)).forEach(file => {
- let name = path.basename(file, ".svg") + suffix
- values[name] = { name, fullPath: path.join(iconsDir, dir, file) }
- })
- })
- matchComponents({
- "hero": ({ name, fullPath }) => {
- let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "")
- content = encodeURIComponent(content)
- let size = theme("spacing.6")
- if (name.endsWith("-mini")) {
- size = theme("spacing.5")
- } else if (name.endsWith("-micro")) {
- size = theme("spacing.4")
- }
- return {
- [`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
- "-webkit-mask": `var(--hero-${name})`,
- "mask": `var(--hero-${name})`,
- "mask-repeat": "no-repeat",
- "background-color": "currentColor",
- "vertical-align": "middle",
- "display": "inline-block",
- "width": size,
- "height": size
- }
- }
- }, { values })
- })
- ]
-}
diff --git a/config/config.exs b/config/config.exs
index 1e439c62..56c6782f 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -47,14 +47,13 @@ config :esbuild,
# Configure tailwind (the version is required)
config :tailwind,
- version: "3.4.17",
+ version: "4.0.9",
music_library: [
args: ~w(
- --config=tailwind.config.js
- --input=css/app.css
- --output=../priv/static/assets/app.css
+ --input=assets/css/app.css
+ --output=priv/static/assets/app.css
),
- cd: Path.expand("../assets", __DIR__)
+ cd: Path.expand("..", __DIR__)
]
# Configures Elixir's Logger
diff --git a/mix.exs b/mix.exs
index 5de5bf50..b4c3f4f3 100644
--- a/mix.exs
+++ b/mix.exs
@@ -65,7 +65,7 @@ defmodule MusicLibrary.MixProject do
# Dev tooling
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
- {:tailwind, "~> 0.2", runtime: Mix.env() == :dev},
+ {:tailwind, "~> 0.3", runtime: Mix.env() == :dev},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
# HTTP Clients
diff --git a/mix.lock b/mix.lock
index b26cb3ec..490104a2 100644
--- a/mix.lock
+++ b/mix.lock
@@ -44,7 +44,7 @@
"recon": {:hex, :recon, "2.5.6", "9052588e83bfedfd9b72e1034532aee2a5369d9d9343b61aeb7fbce761010741", [:mix, :rebar3], [], "hexpm", "96c6799792d735cc0f0fd0f86267e9d351e63339cbe03df9d162010cefc26bb0"},
"req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"},
"table_rex": {:hex, :table_rex, "4.1.0", "fbaa8b1ce154c9772012bf445bfb86b587430fb96f3b12022d3f35ee4a68c918", [:mix], [], "hexpm", "95932701df195d43bc2d1c6531178fc8338aa8f38c80f098504d529c43bc2601"},
- "tailwind": {:hex, :tailwind, "0.2.4", "5706ec47182d4e7045901302bf3a333e80f3d1af65c442ba9a9eed152fb26c2e", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "c6e4a82b8727bab593700c998a4d98cf3d8025678bfde059aed71d0000c3e463"},
+ "tailwind": {:hex, :tailwind, "0.3.1", "a89d2835c580748c7a975ad7dd3f2ea5e63216dc16d44f9df492fbd12c094bed", [:mix], [], "hexpm", "98a45febdf4a87bc26682e1171acdedd6317d0919953c353fcd1b4f9f4b676a2"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
"telemetry_metrics": {:hex, :telemetry_metrics, "1.1.0", "5bd5f3b5637e0abea0426b947e3ce5dd304f8b3bc6617039e2b5a008adc02f8f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7b79e8ddfde70adb6db8a6623d1778ec66401f366e9a8f5dd0955c56bc8ce67"},
"telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},