From bdcc3e1112fa0cbb7b5f8e9b6b6716cba2ff2a39 Mon Sep 17 00:00:00 2001 From: Magnus Madsen Date: Sat, 15 Aug 2026 09:26:29 +0200 Subject: [PATCH] refactor: introduce a Feature component for the code-and-text rows Every row of the feature tour on the front page was the same twelve lines of Bootstrap grid and card markup around a snippet and a few paragraphs, with the two columns swapped by hand every other row. Feature.astro takes the title, the Flix source and a codeLeft boolean, and slots the prose; a named "code" slot covers the two rows whose code column holds more than a single snippet. The text is always first in the markup and codeLeft is order-md-first on the code column, so on a narrow screen every feature now reads heading, text, code, where the code-left rows used to put a bare snippet above its own heading. Desktop rendering is unchanged: the built index.html was diffed before and after with the columns compared as an unordered pair. Co-Authored-By: Claude Fable 5 --- src/components/Feature.astro | 37 ++ src/pages/index.astro | 790 +++++++++++++---------------------- src/styles/global.css | 8 + 3 files changed, 330 insertions(+), 505 deletions(-) create mode 100644 src/components/Feature.astro diff --git a/src/components/Feature.astro b/src/components/Feature.astro new file mode 100644 index 0000000..9de4b86 --- /dev/null +++ b/src/components/Feature.astro @@ -0,0 +1,37 @@ +--- +import CodeSnippet from "./CodeSnippet.astro"; + +interface Props { + title: string; + /** Flix source, shown highlighted beside the text. Anything else that + belongs in the code column -- a manifest, terminal output, a second + snippet -- goes in the "code" slot, which renders under this. */ + code?: string; + /** The code sits to the right of the text unless this is set. The text + comes first in the markup either way, so on a narrow screen every feature + reads heading, text, code, whichever side the code takes on a wide one. */ + codeLeft?: boolean; +} + +const { title, code, codeLeft = false } = Astro.props; +--- + +{/* One row of the feature tour on the front page: a heading and a paragraph + or two beside the code that shows the feature off. The card is borderless + and there only for the inset its body gives the text; global.css takes the + bottom margin off whatever ends the slot, so the paragraphs can be plain +

s rather than Bootstrap's .card-text. */} +

+
+
+
+

{title}

+ +
+
+
+
+ {code && } + +
+
diff --git a/src/pages/index.astro b/src/pages/index.astro index 0d3dbf1..4748cd7 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -3,6 +3,7 @@ import Layout from "../layouts/Layout.astro"; import CodeSnippet from "../components/CodeSnippet.astro"; import PlainSnippet from "../components/PlainSnippet.astro"; import Carousel from "../components/Carousel.astro"; +import Feature from "../components/Feature.astro"; import { httpExample, adtExample, @@ -91,533 +92,312 @@ const vscodeSlides = [
-
-
- -
-
-
-
-
-

Algebraic Data Types and Pattern Matching

-
-

- Algebraic data types and pattern matching are the bread-and-butter - of functional programming and are supported by Flix with minimal - fuss. -

-
-
-
-
+ +

+ Algebraic data types and pattern matching are the bread-and-butter of + functional programming and are supported by Flix with minimal fuss. +

+
-
-
-
-
-

Tuples and Records

-

Flix has built-in support for tuples and records.

-

Records use structural typing and are extensible.

-
-
-
-
- -
-
+ +

Flix has built-in support for tuples and records.

+

Records use structural typing and are extensible.

+
-
-
- -
-
-
-
-

Purity and Impurity

-

- Flix precisely tracks the purity of every expression in a program. -

-

- The Flix compiler provides an ironclad guarantee that if an - expression is pure then it cannot have side-effects and it is - referentially transparent. -

-
-
-
-
+ +

Flix precisely tracks the purity of every expression in a program.

+

+ The Flix compiler provides an ironclad guarantee that if an expression + is pure then it cannot have side-effects and it is referentially + transparent. +

+
-
-
-
-
-

Polymorphic Effects

-

- Flix is able to track purity through higher-order effect - polymorphic functions. -

-

- For example, Flix knows that the purity of List.map depends - on the purity of its function argument f. -

-
-
-
-
- -
-
+ +

+ Flix is able to track purity through higher-order effect polymorphic + functions. +

+

+ For example, Flix knows that the purity of List.map depends on + the purity of its function argument f. +

+
-
-
- -
-
-
-
-

Algebraic Effects

-

- Flix supports algebraic effects, i.e. user-defined effects and - handlers. In particular, Flix supports multi-shot resumptions. -

-

- Effect-oriented programming, with algebraic effects, allows - programmers to write pure functions modulo effects. Effect - handlers enable program reasoning, modularity, and testability. -

-

- For example, the program on the left expresses a greeting function that is pure modulo the current time of the day. In main we call the function and handle the HourOfDay effect - by getting the real-world time from Java's LocalDateTime. -

-
-
-
-
+ +

+ Flix supports algebraic effects, i.e. user-defined effects and handlers. + In particular, Flix supports multi-shot resumptions. +

+

+ Effect-oriented programming, with algebraic effects, allows programmers + to write pure functions modulo effects. Effect handlers enable program + reasoning, modularity, and testability. +

+

+ For example, the program on the left expresses a greeting function + that is pure modulo the current time of the day. In main we call + the function and handle the HourOfDay effect by getting the real-world + time from Java's LocalDateTime. +

+
-
-
-
-
-

Library Effects

-

- The Flix Standard Library comes with a rich collection of - built-in effects, including Clock, Console, Env, FileSystem, Http, Logger, Process, and Random. -

-

- Every library effect has a default handler, hence programs can - use it without any handler boilerplate. -

-

- Library effects support composable middleware: HTTP requests can - be configured with retries and circuit breakers, and the - filesystem can be sandboxed, made read-only, or replaced with an - in-memory implementation, e.g. for testing. -

-
-
-
-
- -
-
+ +

+ The Flix Standard Library comes with a rich collection of built-in + effects, including Clock, Console, Env, FileSystem, Http, Logger, Process, and Random. +

+

+ Every library effect has a default handler, hence programs can use it + without any handler boilerplate. +

+

+ Library effects support composable middleware: HTTP requests can be + configured with retries and circuit breakers, and the filesystem can be + sandboxed, made read-only, or replaced with an in-memory implementation, + e.g. for testing. +

+
-
-
- -
-
-
-
-

Region-based Local Mutation

-

- Flix supports region-based local mutation, which makes it possible - to implement pure functions that internally use mutable state - and destructive operations, as long as these operations are confined - to the region. -

-

- We can use local mutation when it is more natural to write a - function using mutable data and in a familiar imperative style - while still remaining pure to the outside world. -

-

- We can also use local mutation when it is more efficient to use - mutable data structures, e.g. when implementing a sorting - algorithm. -

-
-
-
-
+ +

+ Flix supports region-based local mutation, which makes it possible to + implement pure functions that internally use mutable state and destructive + operations, as long as these operations are confined to the region. +

+

+ We can use local mutation when it is more natural to write a function + using mutable data and in a familiar imperative style while still + remaining pure to the outside world. +

+

+ We can also use local mutation when it is more efficient to use mutable + data structures, e.g. when implementing a sorting algorithm. +

+
-
-
-
-
-

Mutable Structs

-

- Flix supports mutable structs. Fields are immutable by - default, but can be marked with the mut modifier. - Like all mutable memory in Flix, every struct belongs to a - region. -

-

- Struct fields are unboxed, i.e. primitive fields do not require - indirection. This makes structs a memory-efficient building - block for higher-level data structures, e.g. mutable lists, - stacks, and queues. -

-

- The fields of a struct are only visible from within its - companion module, providing compiler-enforced encapsulation. -

-
-
-
-
- -
-
+ +

+ Flix supports mutable structs. Fields are immutable by default, but can + be marked with the mut modifier. Like all mutable memory in Flix, + every struct belongs to a region. +

+

+ Struct fields are unboxed, i.e. primitive fields do not require + indirection. This makes structs a memory-efficient building block for + higher-level data structures, e.g. mutable lists, stacks, and queues. +

+

+ The fields of a struct are only visible from within its companion + module, providing compiler-enforced encapsulation. +

+
-
-
- -
-
-
-
-

Purity Reflection

-

- Flix supports a meta-programming construct that enables - higher-order functions to inspect the purity of a function - argument and use that information to vary their behavior. -

-

- For example, the DelayList.map function varies its behavior - between eager and lazy evaluation depending on the purity of its function - argument. -

-

- We can exploit purity reflection to selectively use lazy or - parallel evaluation inside a library without changing the - semantics from the point-of-view of the clients. -

-
-
-
-
+ +

+ Flix supports a meta-programming construct that enables higher-order + functions to inspect the purity of a function argument and use that + information to vary their behavior. +

+

+ For example, the DelayList.map function varies its behavior between + eager and lazy evaluation depending on the purity of its function argument. +

+

+ We can exploit purity reflection to selectively use lazy or parallel + evaluation inside a library without changing the semantics from the + point-of-view of the clients. +

+
-
-
-
-
-

Parallelism

-

- Flix makes it simple and easy to evaluate pure code in parallel. -

-

- For example, the code on the right shows a parallel implementation - of the List.map function using the par construct. -

-

- Internally, the par construct uses light-weight VirtualThreads. -

-
-
-
-
- -
-
+ +

+ Flix makes it simple and easy to evaluate pure code in parallel. +

+

+ For example, the code on the right shows a parallel implementation of + the List.map function using the par construct. +

+

+ Internally, the par construct uses light-weight VirtualThreads. +

+
-
-
- -
-
-
-
-

Structured Concurrency

-

- Flix supports structured concurrency. -

-

- For example, the code on the left shows the creation of a fresh - region named rc in which two threads are spawned. -

-

- Importantly, control-flow does not leave the region before both threads have terminated. Hence the two threads cannot outlive the - lifetime of their enclosing region. -

-
-
-
-
+ +

+ Flix supports structured concurrency. +

+

+ For example, the code on the left shows the creation of a fresh region + named rc in which two threads are spawned. +

+

+ Importantly, control-flow does not leave the region before both threads + have terminated. Hence the two threads cannot outlive the lifetime of their + enclosing region. +

+
-
-
-
-
-

Traits

-

- Flix uses traits to abstract over types that support a common set - of operations. -

-

- For example, the Eq trait captures the notion of equality - and is used throughout the standard library. -

-
-
-
-
- -
-
+ +

+ Flix uses traits to abstract over types that support a common set of + operations. +

+

+ For example, the Eq trait captures the notion of equality and + is used throughout the standard library. +

+
-
-
- -
-
-
-
-

Higher-Kinded Types

-

- Flix supports higher-kinded types making it possible to abstract - over type constructors. For example, both Option and List implement Foldable. -

-

- The Flix standard library ships with many common traits, such as Monoid, Functor, and Foldable. -

-
-
-
-
+ +

+ Flix supports higher-kinded types making it possible to abstract over + type constructors. For example, both Option and List implement Foldable. +

+

+ The Flix standard library ships with many common traits, such as Monoid, Functor, and Foldable. +

+
-
-
-
-
-

Associated Types

-

- Flix supports associated types, which allow the types in instance - signatures to depend on the instance type. -

-

- The code on the right defines a trait with an associated type Elm, which enables each Coll instance to define its element - type. -

-
-
-
-
- -
-
+ +

+ Flix supports associated types, which allow the types in instance + signatures to depend on the instance type. +

+

+ The code on the right defines a trait with an associated type Elm, which enables each Coll instance to define its element type. +

+
-
-
- -
-
-
-
-

Associated Effects

-

- Associated effects allow the effects in trait members to depend on - the instance type. This makes it easy to create abstractions over - both pure and effectful operations, and mutable and immutable data - structures. -

-

- The code on the left adds an associated effect Aef to - the Coll trait, which makes it possible to add - instances for mutable collections. -

-
-
-
-
+ +

+ Associated effects allow the effects in trait members to depend on the + instance type. This makes it easy to create abstractions over both pure + and effectful operations, and mutable and immutable data structures. +

+

+ The code on the left adds an associated effect Aef to the Coll trait, which makes it possible to add instances for mutable collections. +

+
-
-
-
-
-

Monadic For-Yield

-

- Flix supports a monadic forM-yield construct similar to - Scala's for-comprehensions and Haskell's do notation. - The forM construct is syntactic sugar for uses of point and flatMap (which are provided by the Monad trait). -

-
-
-
-
- -
-
+ +

+ Flix supports a monadic forM-yield construct similar to + Scala's for-comprehensions and Haskell's do notation. + The forM construct is syntactic sugar for uses of point and flatMap (which are provided by the Monad trait). +

+
-
-
- -
-
-
-
-

Applicative For-Yield

-

- In addition to the monadic forM expression, Flix supports - an applicative forA expression that builds on the Applicative trait. The forA construct makes it simple to write error-handling - code which uses the Validation[e, t] data type. -

-
-
-
-
+ +

+ In addition to the monadic forM expression, Flix supports an + applicative forA expression that builds on the Applicative trait. The forA construct makes it simple to write error-handling + code which uses the Validation[e, t] data type. +

+
-
-
-
-
-
-

Seamless Java Interoperability

-
-

- Flix supports seamless Java interoperability, making it possible - to reuse code from the Java Standard Library and the Java - ecosystem, e.g., via Maven. -

-

- Java support includes object creation, method invocation, - exceptions, and class/interface extension. -

-
-
-
-
- -
-
+ +

+ Flix supports seamless Java interoperability, making it possible to + reuse code from the Java Standard Library and the Java ecosystem, e.g., + via Maven. +

+

+ Java support includes object creation, method invocation, exceptions, + and class/interface extension. +

+
-
-
- -
-
-
-
-

Termination Checking

-

- Flix supports the @Terminates annotation, which - asks the compiler to verify that a function is structurally - recursive — and hence guaranteed to terminate on all - inputs. -

-

- The compiler checks that every recursive call is on a strict - substructure of a formal parameter. The check supports tree - recursion, functions with multiple parameters, local - definitions, and higher-order functions. -

-
-
-
-
+ +

+ Flix supports the @Terminates annotation, which asks the compiler + to verify that a function is structurally recursive — and hence guaranteed + to terminate on all inputs. +

+

+ The compiler checks that every recursive call is on a strict + substructure of a formal parameter. The check supports tree recursion, + functions with multiple parameters, local definitions, and higher-order + functions. +

+
-
-
-
-
-

Build and Package Management

-

- Flix has its own build tool and package manager. A project is - described by a single flix.toml manifest, shown on - the right, and flix init writes the first one for - you. -

-

- Dependencies are Flix packages published on GitHub, or JARs - published on Maven — so pulling in the Java ecosystem is one - line in the manifest. Flix resolves both, transitively, and - downloads them on the next build. -

-

- The commands check, build, run, test, build-fatjar, and release are built into the compiler itself, and each one works from the command - line, from the REPL, and from Visual Studio Code. -

-
-
-
-
+ + -
-
+ +

+ Flix has its own build tool and package manager. A project is described + by a single flix.toml manifest, shown on the right, and flix init writes the first one for you. +

+

+ Dependencies are Flix packages published on GitHub, or JARs published on + Maven — so pulling in the Java ecosystem is one line in the + manifest. Flix resolves both, transitively, and downloads them on the + next build. +

+

+ The commands check, build, run, test, build-fatjar, and release are built into the + compiler itself, and each one works from the command line, from the REPL, + and from Visual Studio Code. +

+ -
-
- - -
-
-
-
-

Built-in Test Framework

-

- Flix comes with a built-in test framework. A test is a function - marked with the @Test annotation that takes no - arguments and returns Unit. -

-

- Assertions come from the Assert module in the - standard library. Asserting is itself an effect, so a test - carries Assert in its signature and the test runner - is nothing more than its handler. -

-

- Run every test in a project with flix test, or run - them one at a time from the code lens above each test in Visual - Studio Code. -

-
-
-
-
+ + +

+ Flix comes with a built-in test framework. A test is a function marked + with the @Test annotation that takes no arguments and + returns Unit. +

+

+ Assertions come from the Assert module in the standard library. + Asserting is itself an effect, so a test carries Assert in its + signature and the test runner is nothing more than its handler. +

+

+ Run every test in a project with flix test, or run them one + at a time from the code lens above each test in Visual Studio Code. +

+
diff --git a/src/styles/global.css b/src/styles/global.css index 3b940d4..5c41617 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -282,6 +282,14 @@ h4, .h4 { font-size: 1.2rem; } +/* The feature rows on the front page slot plain paragraphs into a card body. + Bootstrap only trims the bottom margin off a last paragraph that is a + .card-text, so do it here for whatever comes last, or the final

would + add its 1rem to the padding the body already has below it. */ +.feature-text > :last-child { + margin-bottom: 0; +} + /* Bootstrap 5 removed .card-columns. These are Bootstrap 4's rules, kept because four sections of the principles page are laid out with them. */ .card-columns .card {