diff --git a/assets/components/categories.jsx b/assets/components/categories.jsx index 3e61ee5..86fd761 100644 --- a/assets/components/categories.jsx +++ b/assets/components/categories.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React from 'react' import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react' import { CheckIcon, diff --git a/assets/components/commands.jsx b/assets/components/commands.jsx index 7b07e95..d544beb 100644 --- a/assets/components/commands.jsx +++ b/assets/components/commands.jsx @@ -1,22 +1,7 @@ import React, { useState, useEffect } from 'react' -import { createRoot } from "react-dom/client"; +import { createRoot } from "react-dom/client" import { motion, useAnimate, stagger } from 'framer-motion' -const container = { - hidden: { opacity: 0 }, - show: { - opacity: 1, - transition: { - staggerChildren: 0.1 - } - } -} - -const character = { - hidden: { opacity: 0 }, - show: { opacity: 1 } -} - const tabs = [ { title: 'Logs', diff --git a/assets/components/products.jsx b/assets/components/products.jsx new file mode 100644 index 0000000..c4e2425 --- /dev/null +++ b/assets/components/products.jsx @@ -0,0 +1,47 @@ +import React from 'react' +import { createRoot } from "react-dom/client" +import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react' +import { + CheckIcon, + ChevronUpDownIcon, +} from '@heroicons/react/16/solid' + +function Products({ products, interval, selected }) { + return ( + + + {products.find(({ reference }) => reference === selected)?.name || products[0].name} + + + + {products.map((product) => ( + + + +

{product.name}

+
+
+ ))} +
+
+ ) +} + +export function mountProducts() { + const domNode = this.el; + const root = createRoot(domNode); + let { products, interval, selected } = this.el.dataset; + + products = JSON.parse(products); + + root.render() +} \ No newline at end of file diff --git a/assets/js/app.jsx b/assets/js/app.jsx index 383b2cf..7a4f88d 100644 --- a/assets/js/app.jsx +++ b/assets/js/app.jsx @@ -35,6 +35,7 @@ import { Technologies } from '../components/technologies'; import { SSHAccess } from '../components/access'; import { Timeline } from '../components/rollback'; import { mountCommands } from '../components/commands'; +import { mountProducts } from '../components/products'; function mountTimeline() { const domNode = this.el; @@ -169,6 +170,11 @@ Hooks.MountCategories = { updated: mountCategories, } +Hooks.MountProducts = { + mounted: mountProducts, + updated: mountProducts, +} + let csrfToken = document .querySelector("meta[name='csrf-token']") .getAttribute("content"); diff --git a/lib/opsmaru/content/product.ex b/lib/opsmaru/content/product.ex index 5ca78d1..b833004 100644 --- a/lib/opsmaru/content/product.ex +++ b/lib/opsmaru/content/product.ex @@ -2,6 +2,8 @@ defmodule Opsmaru.Content.Product do use Ecto.Schema import Ecto.Changeset + @derive {Jason.Encoder, only: [:index, :reference, :name]} + @valid_attrs ~w(id index reference name)a embedded_schema do diff --git a/lib/opsmaru_web/components/pricing_components.ex b/lib/opsmaru_web/components/pricing_components.ex index 61f63b5..55568ee 100644 --- a/lib/opsmaru_web/components/pricing_components.ex +++ b/lib/opsmaru_web/components/pricing_components.ex @@ -111,6 +111,7 @@ defmodule OpsmaruWeb.PricingComponents do attr :products, :list, required: true attr :features, :list, required: true attr :product_features, :list, required: true + attr :focus_product, :string, default: nil def matrix(assigns) do ~H""" @@ -120,7 +121,9 @@ defmodule OpsmaruWeb.PricingComponents do <.display :for={product <- @products} + product={product} feature={feature} + focus_product={@focus_product} product_feature={match_product_feature(@product_features, product, feature)} /> @@ -128,11 +131,16 @@ defmodule OpsmaruWeb.PricingComponents do end attr :feature, Content.Feature, required: true + attr :product, Content.Product, required: true attr :product_feature, Products.Feature, default: nil + attr :focus_product, :string, default: nil def display(assigns) do ~H""" - +
{@product_feature.remark}
diff --git a/lib/opsmaru_web/live/blog_live/index.ex b/lib/opsmaru_web/live/blog_live/index.ex index 4c334b8..0b385bd 100644 --- a/lib/opsmaru_web/live/blog_live/index.ex +++ b/lib/opsmaru_web/live/blog_live/index.ex @@ -48,7 +48,7 @@ defmodule OpsmaruWeb.BlogLive.Index do
diff --git a/lib/opsmaru_web/live/pricing_live.ex b/lib/opsmaru_web/live/pricing_live.ex index 911c72f..7c4bd02 100644 --- a/lib/opsmaru_web/live/pricing_live.ex +++ b/lib/opsmaru_web/live/pricing_live.ex @@ -45,6 +45,7 @@ defmodule OpsmaruWeb.PricingLive do attr :main_nav, Content.Navigation, required: true attr :interval, :string, default: "month" attr :products, :list, default: [] + attr :focus_product, :string, default: nil def render(assigns) do ~H""" @@ -124,7 +125,15 @@ defmodule OpsmaruWeb.PricingLive do -
+
+
<.link @@ -162,6 +171,7 @@ defmodule OpsmaruWeb.PricingLive do @@ -219,7 +229,7 @@ defmodule OpsmaruWeb.PricingLive do end @impl true - def handle_params(%{"interval" => interval}, _uri, %{assigns: assigns} = socket) do + def handle_params(%{"interval" => interval} = params, _uri, %{assigns: assigns} = socket) do prices = load_prices(interval) active_products_names = Enum.map(prices, & &1.product.name) @@ -232,16 +242,19 @@ defmodule OpsmaruWeb.PricingLive do product.reference in active_products_names end) + focus_product = Map.get(params, "product", List.first(products).reference) + socket = socket |> assign(:prices, prices) |> assign(:interval, interval) |> assign(:products, products) + |> assign(:focus_product, focus_product) {:noreply, socket} end - def handle_params(_, _uri, %{assigns: assigns} = socket) do + def handle_params(params, _uri, %{assigns: assigns} = socket) do prices = load_prices() active_products_names = Enum.map(prices, & &1.product.name) @@ -253,11 +266,14 @@ defmodule OpsmaruWeb.PricingLive do product.reference in active_products_names end) + focus_product = Map.get(params, "product", List.first(products).reference) + socket = socket |> assign(:prices, prices) |> assign(:interval, "month") |> assign(:products, products) + |> assign(:focus_product, focus_product) {:noreply, socket} end