{"id":30141912,"url":"https://github.com/mattlianje/layoutz","last_synced_at":"2026-01-25T08:09:09.476Z","repository":{"id":305213402,"uuid":"1014511610","full_name":"mattlianje/layoutz","owner":"mattlianje","description":"Simple, beautiful CLI output","archived":false,"fork":false,"pushed_at":"2025-12-31T23:33:18.000Z","size":122587,"stargazers_count":217,"open_issues_count":5,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-01-03T14:54:16.805Z","etag":null,"topics":["cli","dsl","functional-programming","scala","tui"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mattlianje.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-07-05T21:46:18.000Z","updated_at":"2025-12-23T12:20:29.000Z","dependencies_parsed_at":"2025-09-07T03:27:02.647Z","dependency_job_id":null,"html_url":"https://github.com/mattlianje/layoutz","commit_stats":null,"previous_names":["mattlianje/layoutz"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/mattlianje/layoutz","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattlianje%2Flayoutz","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattlianje%2Flayoutz/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattlianje%2Flayoutz/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattlianje%2Flayoutz/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mattlianje","download_url":"https://codeload.github.com/mattlianje/layoutz/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattlianje%2Flayoutz/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28748573,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-25T07:58:02.558Z","status":"ssl_error","status_checked_at":"2026-01-25T07:57:57.153Z","response_time":113,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","dsl","functional-programming","scala","tui"],"created_at":"2025-08-11T05:20:31.254Z","updated_at":"2026-01-25T08:09:09.456Z","avatar_url":"https://github.com/mattlianje.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"pix/layoutz-demo.png\" width=\"700\"\u003e\n\u003c/p\u003e\n\n# \u003cimg src=\"pix/layoutz.png\" width=\"60\"\u003e layoutz\n**Simple, beautiful CLI output 🪶**\n\nBuild declarative and composable sections, trees, tables and dashboards for your consoles. Part of [d4](https://github.com/mattlianje/d4)\n\n## Features\n- Zero dependencies, use **Layoutz.scala** like a header-file\n- Effortless composition of elements\n- Thread-safe, purely functional rendering\n\n## Installation\n**layoutz** is on MavenCentral and cross-built for Scala, 2.12, 2.13, 3.x\n```scala\n\"xyz.matthieucourt\" %% \"layoutz\" % \"0.1.0\"\n```\nOr try in REPL:\n```bash\nscala-cli repl --scala 3 --dep xyz.matthieucourt:layoutz_3:0.1.0\n```\n\nAll you need:\n```scala\nimport layoutz._\n```\n\n## Quickstart\n```scala\nimport layoutz._\n\nval dashboard = layout(\n  section(\"System Status\")(\n    row(\n      statusCard(\"CPU\", \"45%\"),\n      statusCard(\"Memory\", \"78%\"), \n      statusCard(\"Disk\", \"23%\")\n    )\n  ),\n  box(\"Recent Activity\")(\n    bullets(\n      \"User alice logged in\",\n      \"Database backup completed\", \n      \"3 new deployments\"\n    )\n  )\n)\n\nprintln(dashboard.render)\n```\nyields:\n```\n=== System Status ===\n┌───────┐ ┌──────────┐ ┌────────┐\n│ CPU   │ │ Memory   │ │ Disk   │\n│ 45%   │ │ 78%      │ │ 23%    │\n└───────┘ └──────────┘ └────────┘\n\n┌───────Recent Activity───────┐\n│ • User alice logged in      │\n│ • Database backup completed │\n│ • 3 new deployments         │\n└─────────────────────────────┘\n```\n\n## Motivation\n- We have `s\"...\"`, and full-blown TUI libraries - but there is a gap in-between.\n- With LLM's, boilerplate code that formats \u0026 \"pretty-prints\" is **_cheaper than ever_**...\n- Thus, **_more than ever_**, \"string formatting code\" is spawning, and polluting domain logic\n- Utlimately, **layoutz** is just a tiny, declarative DSL to combat this\n\n## Core concepts\n- Every piece of content is an `Element`\n- Elements are **immutable** and **composable** - you build complex layouts by combining simple elements.\n- A `layout` is just a special element that arranges other elements **vertically** with consistent spacing:\n```scala\nlayout(elem1, elem2, elem3)  /* Joins with \"\\n\\n\" */\n```\nCall `.render` on an element to get a String\n\nThe power comes from **uniform composition**, since everything is an `Element`, everything can be combined with everything else.\n\n## Elements\nAll components implementing the Element interface you can use in your layouts...\n\n### Text: `Text`\n**layoutz** implicitly converts Strings to `Text` element\n```scala\n\"Simple text\" // \u003c- valid Element\nText(\"Simple text\") // \u003c- you don't need to do this\n```\nthis lets you splice strings into layouts as you build them with var-arg shorthand\n\n### Line Break: `br`\nAdd extra line-break \"\\n\" with `br`:\n```scala\nlayout(\"Line 1\", br, \"Line 2\")\n```\n\n### Section: `section`\n```scala\nsection(\"Config\")(kv(\"env\" -\u003e \"prod\"))\n```\n```\n=== Config ===\nenv : prod\n```\n\n### Layout (vertical): `layout`\n```scala\nlayout(\"First\", \"Second\", \"Third\")\n```\n```\nFirst\n\nSecond\n\nThird\n```\n\n### Row (horizontal): `row`\n```scala\nrow(\"Left\", \"Middle\", \"Right\")\n```\n```\nLeft Middle Right\n```\n\n### Horizontal rule: `hr`\n```scala\nhr\nhr(\"~\", 10)\n```\n```\n──────────────────────────────────────────────────\n~~~~~~~~~\n```\n\n### Key-value pairs: `kv`\n```scala\nkv(\"name\" -\u003e \"Alice\", \"role\" -\u003e \"admin\")\n```\n```\nname : Alice\nrole : admin\n```\n\n### Table: `table`\n```scala\ntable(\n  headers = Seq(\"Name\", \"Status\"),\n  rows = Seq(Seq(\"Alice\", \"Online\"), Seq(\"Bob\", \"Away\"))\n)\n```\n```\n┌───────┬────────┐\n│ Name  │ Status │\n├───────┼────────┤\n│ Alice │ Online │\n│ Bob   │ Away   │\n└───────┴────────┘\n```\n\n### Bullets: `bullets`/`bullet`\nSimple bullet list\n```scala\nbullets(\"Task 1\", \"Task 2\", \"Task 3\")\n```\n```\n• Task 1\n• Task 2\n• Task 3\n```\nSingle bullet with nested children\n```scala\nbullet(\"Backend\", \n  bullet(\"API\"),\n  bullet(\"Database\")\n)\n```\n```\n• Backend\n  • API\n  • Database\n```\nComplex nesting\n```scala\nbullets(\n  bullet(\"Frontend\",\n    bullet(\"Components\",\n      bullet(\"Header\"),\n      bullet(\"Footer\")\n    ),\n    bullet(\"Styles\")\n  ),\n  bullet(\"Backend\",\n    bullet(\"API\"),\n    bullet(\"Database\")\n  )\n)\n```\n```\n• Frontend\n  • Components\n    • Header\n    • Footer\n  • Styles\n• Backend\n  • API\n  • Database\n```\nMix bullets with other elements\n```scala\nbullet(\"Status\",\n  \"System online\",\n  inlineBar(\"Health\", 0.95),\n  \"All services running\"\n)\n```\n```\n• Status\n  • System online\n  • Health [███████████████████─] 95%\n  • All services running\n```\n\n### Box: `box`\n```scala\nbox(\"Summary\")(kv(\"total\" -\u003e \"42\"))\n```\n```\n┌──Summary───┐\n│ total : 42 │\n└────────────┘\n```\n\n### Status card: `statusCard`\n```scala\nstatusCard(\"CPU\", \"45%\")\n```\n```\n┌───────┐\n│ CPU   │\n│ 45%   │\n└───────┘\n```\n\n### Progress bar: `inlineBar`\n```scala\ninlineBar(\"Download\", 0.75)\n```\n```\nDownload [███████████████─────] 75%\n```\n\n### Diff block: `diffBlock`\n```scala\ndiffBlock(\n  added = Seq(\"new feature\"),\n  removed = Seq(\"old code\")\n)\n```\n```\nChanges:\n- old code\n+ new feature\n```\n\n### Tree: `tree`/`branch`/`leaf`\n```scala\ntree(\"Project\")(\n  branch(\"src\",\n    branch(\"main\", leaf(\"App.scala\")),\n    branch(\"test\", leaf(\"AppSpec.scala\"))\n  )\n)\n```\n```\nProject\n└── src/\n    ├── main/\n    │   └── App.scala\n    └── test/\n        └── AppSpec.scala\n```\n\n## Working with collections\nThe full power of Scala functional collections is at your fingertips to render your strings with **layoutz**\n```scala\ncase class User(name: String, role: String)\nval users = Seq(User(\"Alice\", \"Admin\"), User(\"Bob\", \"User\"), User(\"Tom\", \"User\"))\n\nval usersByRole = users.groupBy(_.role)\nsection(\"Users by Role\")(\n  layout(\n    usersByRole.map { case (role, roleUsers) =\u003e\n      box(role)(\n        bullets(roleUsers.map(_.name): _*)\n      )\n    }.toSeq: _*\n  )\n)\n```\n```\n=== Users by Role ===\n┌──Admin──┐\n│ • Alice │\n└─────────┘\n\n┌──User──┐\n│ • Bob  │\n│ • Tom  │\n└────────┘\n```\n\n## Inspiration\n- [ScalaTags](https://github.com/com-lihaoyi/scalatags) by Li Haoyi\n- Countless templating libraries via osmosis ...\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmattlianje%2Flayoutz","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmattlianje%2Flayoutz","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmattlianje%2Flayoutz/lists"}