diff --git a/_site/2024-01-10-functional-programming-benefits/index.html b/_site/2024-01-10-functional-programming-benefits/index.html deleted file mode 100644 index 655cbde..0000000 --- a/_site/2024-01-10-functional-programming-benefits/index.html +++ /dev/null @@ -1,260 +0,0 @@ - - - - - - - - - - The Benefits of Functional Programming in Web Development | Llmex Blog - - - - - - - -
- -
- -
-
-

The Benefits of Functional Programming in Web Development

-

In the ever-evolving landscape of web development, functional programming has emerged as a powerful paradigm that offers unique advantages over traditional object-oriented approaches. Today, we'll explore why functional programming, particularly in languages like Elixir, is becoming increasingly popular among web developers.

-

What is Functional Programming?

-

Functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions. It emphasizes:

- -

Key Benefits for Web Development

-

1. Predictability and Debugging

-

One of the most significant advantages of functional programming is predictability. Pure functions make debugging much easier because:

-
# Pure function - always returns the same result
-def calculate_total(items) do
-  Enum.reduce(items, 0, fn item, acc -> 
-    acc + item.price 
-  end)
-end
-
-# Easy to test and debug
-assert calculate_total([%{price: 10}, %{price: 20}]) == 30
-
-

You don't have to worry about hidden state changes or unexpected side effects. What you see is what you get.

-

2. Concurrency and Scalability

-

Functional programming languages like Elixir excel at handling concurrent operations. The Actor Model and immutable data structures make it safe to run thousands of processes simultaneously:

-
# Spawn multiple processes safely
-tasks = for url <- urls do
-  Task.async(fn -> HTTPClient.get(url) end)
-end
-
-# Collect results without race conditions
-results = Task.await_many(tasks)
-
-

This approach is particularly beneficial for web applications that need to handle many simultaneous users or API requests.

-

3. Error Handling and Resilience

-

Functional languages often promote explicit error handling through pattern matching and result types:

-
case UserService.create_user(params) do
-  {:ok, user} -> 
-    render_success(user)
-  {:error, changeset} -> 
-    render_errors(changeset)
-end
-
-

This explicit approach to error handling makes your applications more robust and easier to maintain.

-

4. Code Reusability and Composition

-

Higher-order functions and function composition lead to highly reusable code:

-
# Composable functions
-def process_orders(orders) do
-  orders
-  |> Enum.filter(&valid_order?/1)
-  |> Enum.map(&calculate_tax/1)
-  |> Enum.sort_by(&(&1.total), :desc)
-end
-
-# Each step can be tested and reused independently
-
-

5. Immutability Benefits

-

Immutable data structures prevent many common bugs:

- -
# Original list is never modified
-original_list = [1, 2, 3]
-new_list = Enum.map(original_list, &(&1 * 2))
-
-# original_list is still [1, 2, 3]
-# new_list is [2, 4, 6]
-
-

Real-World Applications

-

API Development

-

Functional programming shines in API development where you need to:

- -
def handle_api_request(conn, params) do
-  with {:ok, validated_params} <- validate_params(params),
-       {:ok, user} <- authenticate_user(conn),
-       {:ok, result} <- process_request(validated_params, user) do
-    json(conn, %{data: result})
-  else
-    {:error, reason} -> 
-      json(conn, %{error: reason})
-  end
-end
-
-

Data Processing Pipelines

-

The pipeline operator and functional composition make data processing elegant:

-
def process_user_analytics(raw_data) do
-  raw_data
-  |> parse_events()
-  |> filter_valid_events()
-  |> group_by_user()
-  |> calculate_metrics()
-  |> format_for_output()
-end
-
-

Real-time Applications

-

With technologies like Phoenix LiveView, functional programming enables powerful real-time features:

-
def handle_event("update_score", %{"score" => score}, socket) do
-  new_state = update_game_state(socket.assigns.game, score)
-  
-  # Broadcast to all connected users
-  broadcast_update(new_state)
-  
-  {:noreply, assign(socket, game: new_state)}
-end
-
-

Getting Started with Functional Web Development

-

If you're interested in exploring functional programming for web development:

-
    -
  1. Start with pure functions - Begin by writing functions without side effects
  2. -
  3. Embrace immutability - Use immutable data structures wherever possible
  4. -
  5. Learn pattern matching - Master this powerful feature for control flow
  6. -
  7. Practice composition - Build complex operations from simple functions
  8. -
  9. Explore functional languages - Try Elixir, Clojure, or functional JavaScript
  10. -
-

Common Misconceptions

-

"Functional Programming is Slower"

-

Modern functional languages are highly optimized. Elixir's BEAM VM, for example, is designed for high concurrency and fault tolerance.

-

"It's Too Academic"

-

While functional programming has academic roots, it's highly practical for real-world applications. Companies like WhatsApp, Discord, and Pinterest use Elixir in production.

-

"Learning Curve is Too Steep"

-

The concepts might be different, but the payoff in code quality and maintainability is worth the initial investment.

-

Conclusion

-

Functional programming offers significant benefits for web development, from improved reliability and scalability to better code organization and testing. While it requires a shift in thinking, the advantages—especially for complex, concurrent applications—make it a valuable approach to master.

-

The web development landscape continues to evolve, and functional programming principles are becoming increasingly important. Whether you choose a purely functional language like Elixir or incorporate functional concepts into your existing toolset, understanding these principles will make you a more effective developer.

-

Ready to dive deeper? Start by exploring functional concepts in your current language, or take the plunge with a functional web framework like Phoenix. The future of web development is functional, and the time to start learning is now.

- - - -
- - -
- - - - - - - - - - - \ No newline at end of file diff --git a/_site/2024-01-15-getting-started-with-tableau/index.html b/_site/2024-01-15-getting-started-with-tableau/index.html deleted file mode 100644 index cbfc578..0000000 --- a/_site/2024-01-15-getting-started-with-tableau/index.html +++ /dev/null @@ -1,247 +0,0 @@ - - - - - - - - - - Getting Started with Tableau: Building Static Sites with Elixir | Llmex Blog - - - - - - - -
- -
- -
-
-

Getting Started with Tableau: Building Static Sites with Elixir

-

Static site generators have revolutionized how we build and deploy websites, offering the perfect balance of performance, security, and developer experience. Today, we're exploring Tableau, a powerful static site generator built specifically for the Elixir ecosystem.

-

Why Tableau?

-

Tableau brings the elegance and power of Elixir to static site generation. Unlike traditional generators written in Ruby or JavaScript, Tableau leverages:

- -

Setting Up Your First Tableau Site

-

Getting started with Tableau is straightforward. First, add it to your mix.exs dependencies:

-
defp deps do
-  [
-    {:tableau, "~> 0.25"},
-    {:phoenix_live_view, "~> 1.0"}
-  ]
-end
-
-

Then create your first layout:

-
defmodule MyBlog.RootLayout do
-  use Tableau.Layout
-  use Phoenix.Component
-
-  def template(assigns) do
-    ~H"""
-    <!DOCTYPE html>
-    <html lang="en">
-      <head>
-        <meta charset="utf-8" />
-        <title><%= @page[:title] %></title>
-      </head>
-      <body>
-        <main>
-          <%= render @inner_content %>
-        </main>
-      </body>
-    </html>
-    """
-    |> Phoenix.HTML.Safe.to_iodata()
-  end
-end
-
-

Creating Pages and Posts

-

Tableau makes it easy to create both static pages and blog posts. Pages are defined as Elixir modules:

-
defmodule MyBlog.Pages.Index do
-  use Tableau.Page,
-    layout: MyBlog.RootLayout,
-    permalink: "/"
-
-  def template(assigns) do
-    ~H"""
-    <h1>Welcome to My Blog</h1>
-    <p>Built with Elixir and Tableau!</p>
-    """
-  end
-end
-
-

Posts can be written in Markdown with frontmatter, just like other static site generators:

-
---
-title: "My First Post"
-date: "2024-01-15"
-layout: MyBlog.PostLayout
----
-
-# Hello, World!
-
-This is my first blog post using Tableau.
-
-

Advanced Features

-

Component Reusability

-

One of Tableau's strongest features is its integration with Phoenix LiveView components. You can create reusable components and use them across your site:

-
defmodule MyBlog.Components.PostCard do
-  use Phoenix.Component
-
-  attr :post, :map, required: true
-
-  def post_card(assigns) do
-    ~H"""
-    <article class="post-card">
-      <h2><%= @post.title %></h2>
-      <time><%= @post.date %></time>
-      <p><%= @post.excerpt %></p>
-    </article>
-    """
-  end
-end
-
-

Data Processing

-

Leverage Elixir's powerful data processing capabilities to transform and filter your content:

-
defmodule MyBlog.Posts do
-  def recent_posts(posts, limit \\ 5) do
-    posts
-    |> Enum.sort_by(& &1.date, {:desc, Date})
-    |> Enum.take(limit)
-  end
-
-  def posts_by_tag(posts, tag) do
-    Enum.filter(posts, &(tag in &1.tags))
-  end
-end
-
-

Performance and SEO

-

Tableau generates fully static HTML, which means:

- -

Deployment

-

Building your site is as simple as running:

-
mix tableau.build
-
-

The generated site will be in the _site directory, ready to deploy to any static hosting service like Netlify, Vercel, or GitHub Pages.

-

Conclusion

-

Tableau brings the power and elegance of Elixir to static site generation. With its integration with Phoenix LiveView, powerful templating system, and functional programming paradigms, it's an excellent choice for developers who want to build fast, maintainable static sites.

-

Whether you're building a personal blog, documentation site, or marketing pages, Tableau provides the tools and flexibility you need while maintaining the reliability and performance that static sites are known for.

-

Ready to get started? Check out the official Tableau documentation and start building your next static site with Elixir!

- - - -
- - -
- - - - - - - - - - - \ No newline at end of file diff --git a/_site/css/simple.css b/_site/css/simple.css deleted file mode 100644 index 3d9081e..0000000 --- a/_site/css/simple.css +++ /dev/null @@ -1,681 +0,0 @@ -/* Copied from the origin (https://github.com/artalar/mono) for fast interaction and fixing. Reatom docs is a good playground form mono. */ - -:root { - --mono-main: #10a040; - --mono-back: #000000; - /* --mono-accent: #007acc; - --mono-muted: #666666; - --mono-border: #cccccc; - --mono-success: #28a745; - --mono-warning: #ffc107; - --mono-error: #dc3545; */ -} - -.mono-all, -.mono, -.mono-all *, -.mono:before, -.mono-all *:before, -.mono:after, -.mono-all *:after { - color: var(--mono-main, #111111); - background-color: var(--mono-back, #eeeeee); - font-family: "Roboto Mono", monospace; - line-height: 2.5rem; - font-size: 1.2rem; - box-sizing: border-box; - - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.mono::selection, -.mono-all *::selection { - color: var(--mono-back); - background-color: var(--mono-main); -} -a.mono, -.mono-all a { - position: relative; - /* margin-right: 0.5rem; */ - text-decoration: none; - outline: none; - border-bottom: 0.25rem solid var(--mono-main); -} -a.mono:hover, -.mono-all a:hover { - border-bottom-width: 0.5rem; -} -a.mono:visited, -.mono-all a:visited { - border-bottom: 0.1rem solid var(--mono-main); -} -a.mono:after, -.mono-all a:after { - content: "00"; - color: transparent; - background-color: var(--mono-main); - clip-path: polygon(25% 25%, 75% 50%, 25% 75%); -} -a.mono:focus:after, -.mono-all a:focus:after { - clip-path: polygon( - 0 0, - 20% 20%, - 20% 80%, - 80% 50%, - 20% 20%, - 0 0, - 100% 0, - 100% 100%, - 0 100% - ); - background-color: unset; - background-image: repeating-linear-gradient( - -45deg, - transparent 0 3px, - var(--mono-main) 3px 5px - ); -} -a.mono:active:after, -.mono-all a:active:after { - background-image: repeating-linear-gradient( - -45deg, - transparent 0 3px, - var(--mono-main) 3px 7px - ); -} - -b.mono, -.mono-all b { - font-weight: 600; - border: 0.2rem solid var(--mono-main); -} - -body.mono, -body.mono-all, -.mono-all body { - margin: 0; - position: relative; - /* min-width: min(calc(100vw + 20rem), 85rem); */ - scroll-snap-type: x mandatory; - display: flex; -} - -main.mono, -.mono-all main { - scroll-snap-align: start; - margin: auto; - /* width: min(100vw, 65rem); */ - display: flex; - flex: 1; - flex-direction: column; - padding: 0 1rem; -} - -aside.mono, -.mono-all aside { - position: sticky; - top: 0; - display: flex; - flex: 1; - flex-direction: column; - /* width: 20rem; - min-width: 20rem; - max-width: 20rem; */ - max-height: 100vh; - overflow-y: scroll; - padding: 1rem; -} -/* TODO: stick it bottom */ -footer.mono, -.mono-all footer { - width: 100%; - display: flex; - justify-content: center; - margin-top: auto; - padding: 1rem; - border-top: 1px solid var(--mono-main); -} - -blockquote.mono, -.mono-all blockquote { - position: relative; - margin: 2rem; - margin-left: 3rem; -} -blockquote.mono:before, -.mono-all blockquote:before { - content: ""; - position: absolute; - top: 0; - left: 0; - height: 1rem; - width: 3rem; - background-color: var(--mono-main); - clip-path: polygon( - 0 0, - calc(100% - 0.25rem) 0, - calc(100% - 0.25rem) 0.25rem, - 100% 0.25rem, - 100% calc(100% - 0.25rem), - 1rem calc(100% - 0.25rem), - 1rem 100%, - 0.25rem 100%, - 0.25rem calc(100% - 0.25rem), - 0 calc(100% - 0.25rem) - ); -} - -button.mono, -.mono-all button { - position: relative; - outline: none; - margin-top: 0.4rem; - margin-bottom: 0.2rem; - border: 0.2rem solid var(--mono-main); - border-top: none; - height: 2rem; - min-width: 5rem; - color: var(--mono-main); - background-color: var(--mono-back); - font-weight: 600; - display: inline-flex; - justify-content: center; - align-items: center; -} -button.mono + button.mono, -.mono-all button + button { - margin-left: 1rem; -} -button.mono:before, -.mono-all button:before { - content: ""; - position: absolute; - top: -0.4rem; - left: -0.2rem; - width: calc(100% + 0.4rem); - height: 0.8rem; - background-color: var(--mono-main); - clip-path: polygon( - 0 30%, - calc(100% - 0.8rem) 30%, - calc(100% - 0.8rem) 0%, - 100% 50%, - calc(100% - 0.8rem) 100%, - calc(100% - 0.8rem) 70%, - 0 70% - ); -} -button.mono:focus:after, -.mono-all button:focus:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: calc(100% + 0.8rem); - height: calc(100% + 0.8rem); - background-image: repeating-linear-gradient( - -45deg, - transparent 0 3px, - var(--mono-main) 3px 5px - ); - clip-path: polygon( - calc(100% - 0.5rem) 0.25rem, - calc(100% - 0.5rem) calc(100% - 0.5rem), - 0.25rem calc(100% - 0.5rem), - 0.25rem 100%, - 100% 100%, - 100% 0.25rem - ); -} -button.mono:active:after, -.mono-all button:active:after { - background-image: repeating-linear-gradient( - -45deg, - transparent 0 3px, - var(--mono-main) 3px 7px - ); -} - -:not(pre) > code.mono, -.mono-all :not(pre) > code { - border: 1px dashed var(--mono-main); - padding: 0 0.25rem; -} -:not(pre) > code.mono:before, -.mono-all :not(pre) > code:before, -:not(pre) > code.mono:after, -.mono-all :not(pre) > code:after { - font-weight: bold; - color: var(--mono-back); - background-color: var(--mono-main); - /* fix empty space when scale */ - box-shadow: 0 0 0 1px var(--mono-main); - /* FIXME: does not work */ - transform: scaleX(0.5); -} - -details.mono, -.mono-all details { - margin: 1rem 0; - padding: 1rem; - padding-left: 1.5rem; - border: 0.2rem solid var(--mono-main); - overflow-x: hidden; -} -details[open].mono summary.mono, -.mono-all details[open] summary { - margin-bottom: 0.5rem; -} -details[open].mono summary.mono::before, -.mono-all details[open] summary::before { - transform: rotate(180deg); -} - -h1.mono, -.mono-all h1, -h2.mono, -.mono-all h2, -h3.mono, -.mono-all h3, -h4.mono, -.mono-all h4 { - border-left: 4px solid var(--mono-main); - border-top: 2px solid var(--mono-main); - padding-top: 0.2em; - padding-left: 0.3em; - margin: 3rem 0 1rem; -} - -h1.mono, -.mono-all h1 { - margin-top: 2rem; - font-size: 2.2em; -} - -h2.mono, -.mono-all h2 { - font-size: 1.6em; -} - -h3.mono, -.mono-all h3 { - font-size: 1.2em; -} - -input[type="checkbox"].mono, -.mono-all input[type="checkbox"] { - position: relative; - top: 0.5em; - margin: 0; - width: 1.5rem; - height: 1.5rem; - margin-right: 0.5rem; - margin-bottom: 1rem; - border-radius: 50%; - box-shadow: inset 0 0 0 1rem var(--mono-main); - outline: none; - cursor: pointer; -} -input[type="checkbox"].mono:before, -.mono-all input[type="checkbox"]:before { - position: absolute; - content: ""; - left: 0.125rem; - top: 0.125rem; - width: 1.25rem; - height: 1.25rem; - background-color: var(--mono-back); - border: 0.25rem solid var(--mono-back); -} -input[type="checkbox"].mono:checked:before, -.mono-all input[type="checkbox"]:checked:before { - background-color: var(--mono-main); -} -input[type="checkbox"].mono:focus:after, -.mono-all input[type="checkbox"]:focus:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: calc(100% + 0.4rem); - height: calc(100% + 0.4rem); - background-image: repeating-linear-gradient( - -45deg, - transparent 0 2px, - var(--mono-main) 2px 3px - ); - clip-path: polygon( - calc(100% - 0.4rem) 0.2rem, - calc(100% - 0.4rem) calc(100% - 0.4rem), - 0.2rem calc(100% - 0.4rem), - 0.2rem 100%, - 100% 100%, - 100% 0.2rem - ); -} -input[type="checkbox"].mono:active:after, -.mono-all input[type="checkbox"]:active:after { - background-image: repeating-linear-gradient( - -45deg, - transparent 0 2px, - var(--mono-main) 2px 4px - ); -} - -input[type="color"].mono, -.mono-all input[type="color"] { - position: relative; - outline: none; - height: 2.5rem; -} -input[type="color"].mono:focus:after, -.mono-all input[type="color"]:focus:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: calc(100% + 0.6rem); - height: calc(100% + 0.6rem); - background-image: repeating-linear-gradient( - -45deg, - transparent 0 3px, - var(--mono-main) 3px 5px - ); - clip-path: polygon( - calc(100% - 0.5rem) 0.25rem, - calc(100% - 0.5rem) calc(100% - 0.5rem), - 0.25rem calc(100% - 0.5rem), - 0.25rem 100%, - 100% 100%, - 100% 0.25rem - ); -} -input[type="color"].mono:active:after, -.mono-all input[type="color"]:active:after { - background-image: repeating-linear-gradient( - -45deg, - transparent 0 3px, - var(--mono-main) 3px 7px - ); -} - -input[type="radio"].mono, -.mono-all input[type="radio"] { - position: relative; - top: 0.5em; - margin: 0; - width: 1.5rem; - height: 1.5rem; - margin-right: 0.5rem; - margin-bottom: 1rem; - border-radius: 50%; - box-shadow: inset 0 0 0 1rem var(--mono-main); - outline: none; - cursor: pointer; -} -input[type="radio"].mono:before, -.mono-all input[type="radio"]:before { - position: absolute; - content: ""; - left: 0.125rem; - top: 0.125rem; - width: 1.25rem; - height: 1.25rem; - background-color: var(--mono-back); - border: 0.15rem solid var(--mono-back); - border-radius: 50%; -} -input[type="radio"].mono:checked:before, -.mono-all input[type="radio"]:checked:before { - background-color: var(--mono-main); -} -input[type="radio"].mono:focus:after, -.mono-all input[type="radio"]:focus:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: calc(100% + 0.4rem); - height: calc(100% + 0.4rem); - background-image: repeating-linear-gradient( - -45deg, - transparent 0 2px, - var(--mono-main) 2px 3px - ); - clip-path: polygon( - calc(100% - 0.4rem) 0.2rem, - calc(100% - 0.4rem) calc(100% - 0.4rem), - 0.2rem calc(100% - 0.4rem), - 0.2rem 100%, - 100% 100%, - 100% 0.2rem - ); -} - -input[type="range"].mono, -.mono-all input[type="range"] { - appearance: none; - -webkit-appearance: none; - outline: none; - position: relative; - border: 0.2rem solid var(--mono-main); - padding: 0.8rem 0.5rem; - height: 1.5rem; - width: 20rem; -} -input[type="range"].mono::-webkit-slider-runnable-track, -.mono-all input[type="range"]::-webkit-slider-runnable-track { - width: 100%; - height: 0.2rem; - cursor: pointer; - background: var(--mono-main); -} -input[type="range"].mono::-webkit-slider-thumb, -.mono-all input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - border: 0.2rem solid var(--mono-main); - height: 1rem; - width: 1rem; - background: var(--mono-back); - cursor: pointer; - margin-top: -0.4rem; -} -input[type="range"].mono:active::-webkit-slider-thumb, -.mono-all input[type="range"]:active::-webkit-slider-thumb { - background-color: var(--mono-main); -} -input[type="range"].mono:focus:after, -.mono-all input[type="range"]:focus:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: calc(100% + 0.7rem); - height: calc(100% + 0.7rem); - background-image: repeating-linear-gradient( - -45deg, - transparent 0 3px, - var(--mono-main) 3px 5px - ); - clip-path: polygon( - calc(100% - 0.5rem) 0.25rem, - calc(100% - 0.5rem) calc(100% - 0.5rem), - 0.25rem calc(100% - 0.5rem), - 0.25rem 100%, - 100% 100%, - 100% 0.25rem - ); -} - -fieldset.mono, -.mono-all fieldset { - border: 0.2rem solid var(--mono-main); -} - -legend.mono, -.mono-all legend { - font-size: 1.4em; -} - -li.mono, -.mono-all li { - list-style: none; - position: relative; -} -li.mono + li.mono, -.mono-all li + li { - margin-top: 1.5rem; -} -li.mono:before, -.mono-all li:before { - content: ""; - position: absolute; - top: 0.75rem; - left: -1.5rem; - width: 1rem; - height: 1rem; - color: var(--mono-back); - background-color: var(--mono-main); - /* box-shadow: 0.4rem -0.4rem 0 -0.1rem var(--mono-main); */ -} - -p.mono:before, -.mono-all p:before { - content: " "; - width: 1.5rem; - display: inline-block; -} - -pre.mono, -.mono-all pre { - position: relative; - flex-shrink: 0; - padding: 0.5rem 1rem; - margin: 1.5rem 0; - border: 2px dashed var(--mono-main); - overflow-x: scroll; - line-height: 2rem; -} - -pre.mono, -pre.mono *, -.mono-all pre, -.mono-all pre * { - line-height: 2rem; - background-color: transparent; -} - -/* pre.mono:hover:before, -.mono-all pre:hover:before { - content: ''; - position: absolute; - top: 0.5rem; - right: 0.5rem; - width: 2.5rem; - height: 2.5rem; - background-color: var(--mono-main); - opacity: 0.7; - clip-path: polygon( - 0 0, - 0 65%, - 65% 65%, - 65% 0, - 100% 0, - 100% 100%, - 35% 100%, - 35% 35%, - 100% 35%, - 100% 0 - ); -} */ - -strong.mono, -.mono-all strong { - font-weight: normal; - box-shadow: - inset 0 -0.2em var(--mono-main), - 0 0.25em 0 0 var(--mono-main); -} - -summary.mono, -.mono-all summary { - display: inline; - position: relative; - margin-right: 100%; - list-style: none; - font-size: 1.4rem; - outline: none; -} -summary.mono:before, -.mono-all summary:before { - content: ""; - position: absolute; - top: -0.5rem; - left: -1.2rem; - width: 0.8rem; - height: calc(100% + 1rem); - background-color: var(--mono-main); - clip-path: polygon( - 25% 0, - 25% calc(100% - 0.6rem), - 0 calc(100% - 0.6rem), - 50% 100%, - 100% calc(100% - 0.6rem), - 75% calc(100% - 0.6rem), - 75% 0 - ); -} -summary.mono:focus:after, -.mono-all summary:focus:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: calc(100% + 0.8rem); - height: calc(100% + 0.4rem); - background-image: repeating-linear-gradient( - -45deg, - transparent 0 3px, - var(--mono-main) 3px 5px - ); - clip-path: polygon( - calc(100% - 0.5rem) 0.25rem, - calc(100% - 0.5rem) calc(100% - 0.5rem), - 0.25rem calc(100% - 0.5rem), - 0.25rem 100%, - 100% 100%, - 100% 0.25rem - ); -} -summary.mono:active:after, -.mono-all summary:active:after { - background-image: repeating-linear-gradient( - -45deg, - transparent 0 3px, - var(--mono-main) 3px 7px - ); -} - -table.mono, -.mono-all table { - display: block; - width: 100%; - width: max-content; - max-width: 100%; - overflow: auto; -} - -td.mono, -.mono-all td, -th.mono, -.mono-all th { - border-top: 0.5rem solid var(--mono-main); - padding: 0 1rem; -} - -ul.mono, -.mono-all ul { - padding-left: 1.5rem; -}