Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions formatter-module/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ inputs.self.library.defaultSystems (
enableDefaultExcludes = true;
projectRootFile = "flake.nix";
programs = {
jsonfmt.enable = true;
mdformat.enable = true;
mdsh.enable = true;
nixfmt.enable = true;
Expand Down
29 changes: 29 additions & 0 deletions package-sets/top-level/matrix-icons/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# NixOS Matrix Room Icons

This directory contains the builder scripts and the sources that generate the icons for NixOS-managed Matrix rooms.

## Creating a New Room Icon

1. Create a new subdirectory inside the `rooms/` directory with your room's alias in the [nixos.org](https://matrix.to/#/#community:nixos.org) space.

- For example, if your new room can be reached with the `#haskell:nixos.org` address, you would name the subdirectory `haskell`.

2. Inside your new subdirectory, create a file named `icon.json`. This file determines how your icon will be generated from the default templates.

- See the "`icon.json` Syntax" section below for more information on the valid fields for the `icon.json` file.

3. Build your new icon with `nix build .#matrix-icons.your-room-name`. Following the same example above, you would build the `#haskell:nixos.org` room icon with `nix build .#matrix-icons.haskell`.

- You can also build all room icons at once using `nix build .#matrix-icons`.

## `icon.json` Syntax

<!-- TODO: @sigmasquadron: How to best expose the full schema for `icon.json`? It would be great if there was some magic hidden file that code editors picked up automatically or something. -->

## Custom Assets

<!-- TODO: @sigmasquadron: Explain how to add .svg images to be embedded in the room icon. -->

## Examples

<!-- TODO: @sigmasquadron: Add a table with examples. -->
124 changes: 124 additions & 0 deletions package-sets/top-level/matrix-icons/main.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Date must be set to none for deterministic builds
#set document(date: none)
#set page(margin: 0pt, width: 2048pt, height: 2048pt)

#let data = json("final.json")

#let palette-colour(intOrStr) = if type(intOrStr) == int {
if intOrStr == 0 { luma(0) } else if intOrStr == 1 {
luma(255)
} else if intOrStr == 2 { rgb("#5b7ec8") } else if intOrStr == 3 {
rgb("#87adfa")
} else if intOrStr == 4 { rgb("#5fb8f2") } else if intOrStr == 5 {
rgb("#aaa1f6")
} else if intOrStr == 6 { rgb("#e99861") } else if intOrStr == 7 {
rgb("#f08d94")
} else if intOrStr == 8 { rgb("#d991d2") } else if intOrStr == 9 {
rgb("#6fc488")
} else { panic("Invalid Colour ID: " + intOrStr) }
} else { rgb(intOrStr) }

// https://typst.app/universe/package/one-liner
#let fit-to-width(max-text-size: 800pt, min-text-size: 256pt, it) = context {
let contentsize = measure(it)
layout(size => {
if contentsize.width > 0pt {
// Prevent failure on empty content
let ratio-x = size.width / contentsize.width
let ratio-y = size.height / contentsize.height
let ratio = if ratio-x < ratio-y {
ratio-x
} else {
ratio-y
}

let newx = contentsize.width * ratio
let newy = contentsize.height * ratio
let suggestedtextsize = 1em * ratio
if (suggestedtextsize + 0pt).to-absolute() > max-text-size {
suggestedtextsize = max-text-size
}
if (suggestedtextsize + 0pt).to-absolute() < min-text-size {
suggestedtextsize = min-text-size
}
set text(size: suggestedtextsize)
it
}
})
}

#let icon(
type: none,
colours: none,
contents: none,
) = {
set page(
fill: palette-colour(if type == "standard" { colours.background } else {
colours.border
}),
background: {
if type == "standard" {
grid(
columns: 1,
rows: (992pt, 64pt, 992pt),
gutter: 0pt,
rect(
width: 100%,
height: 100%,
stroke: none,
inset: if contents.style == "text" { 128pt } else { 0pt },
if contents.style == "text" {
align(center + bottom, fit-to-width(text(
font: "Route 159",
weight: "bold",
fill: palette-colour(colours.text),
contents.text,
)))
} else if contents.style == "image" {
align(center + bottom, image(
{ "icons/" + contents.image + ".svg" },
height: 992pt,
fit: "contain",
))
} else { panic("Invalid style: " + content.style) },
),

rect(width: 100%, height: 100%, fill: palette-colour(colours.border)),

rect(
width: 100%,
height: 100%,
fill: palette-colour(2),
inset: 0pt,
image(
"icons/nixos-logomark-white-flat-minimal.svg",
fit: "contain",
),
),
)
} else {
circle(
radius: 768pt,
fill: palette-colour(colours.background),
inset: -224pt,
image({ "icons/" + contents.image + ".svg" }, fit: "contain"),
)
}
},
)
pagebreak(weak: true)
// FIXME: For some reason, the icons aren't generated correctly if there isn't *something* in the first page.
text(fill: rgb("#00000000"), [.])
}

#if sys.inputs.singleIcon == "null" {
for room in data.values() {
icon(type: room.type, colours: room.colours, contents: room.contents)
}
} else {
icon(
type: data.at(sys.inputs.singleIcon).type,
colours: data.at(sys.inputs.singleIcon).colours,
contents: data.at(sys.inputs.singleIcon).contents,
)
}
113 changes: 113 additions & 0 deletions package-sets/top-level/matrix-icons/package.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{
jq,
jura,
lib,
matrix-icons,
nixos-branding,
efficient-compression-tool,
route159,
symlinkJoin,
typix-lib,

singleIcon ? null,
}:

let
inherit (builtins)
readDir
;
inherit (lib.asserts)
assertOneOf
;
inherit (lib.attrsets)
attrNames
attrValues
genAttrs
removeAttrs
;
inherit (lib.fileset)
toSource
unions
;
inherit (typix-lib)
buildDeterministicTypstProject
;

typstSource = "main.typ";
listOfRooms = attrNames (readDir ./rooms);
in

assert assertOneOf "The selected room icon" singleIcon ([ null ] ++ listOfRooms);

buildDeterministicTypstProject {
pname = "matrix-icons";
version = "0.1.0";

src = toSource {
root = ./.;
fileset = unions [ ./main.typ ];
};

nativeBuildInputs = [
jq
efficient-compression-tool
];

inherit typstSource;

fontPaths = [
"${jura}/share/fonts/truetype/jura"
"${route159}/share/fonts/opentype/route159"
];

virtualPaths = [
{
dest = "icons";
src = "${symlinkJoin {
name = "helper-icons";
paths = (
attrValues (
removeAttrs nixos-branding.artifacts.media-kit [
"callPackage"
"newScope"
"overrideScope"
"packages"
"recurseForDerivations"
]
)
);
postBuild = ''
find ${./rooms} -type f -name "*.svg" -exec cp {} $out \;
'';
}}";
}
];

buildPhaseTypstCommand = ''
find ${./rooms} -type f -name icon.json -print0 | xargs -0 jq -n 'reduce inputs as $item ({}; . + { (input_filename | split("/")[4]): $item })' >> final.json
typst compile \
--format png \
--input singleIcon=${if (isNull singleIcon) then "null" else singleIcon} \
${typstSource} "{p}.png"
'';

installPhaseCommand = ''
mkdir $out
${
if (isNull singleIcon) then
''
paste \
<(jq -r 'keys[]' final.json) \
<(find . -maxdepth 1 -type f -name '*.png' -printf '%f\n') \
| while IFS=$'\t' read key png; do
mv -- "$png" "$out/$key.png"
done
''
else
"mv 1.png $out/${singleIcon}.png"
}
ect -9 -keep --strip --strict $out
'';

passthru = genAttrs listOfRooms (name: matrix-icons.override { singleIcon = name; });
}
1 change: 1 addition & 0 deletions package-sets/top-level/matrix-icons/rooms/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!*.svg
12 changes: 12 additions & 0 deletions package-sets/top-level/matrix-icons/rooms/dev/icon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"type": "standard",
"colours": {
"background": 1,
"border": 3,
"text": 2
},
"contents": {
"style": "text",
"text": "dev"
}
}
11 changes: 11 additions & 0 deletions package-sets/top-level/matrix-icons/rooms/kde/icon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"type": "standard",
"colours": {
"background": 4,
"border": 1
},
"contents": {
"style": "image",
"image": "kde"
}
}
1 change: 1 addition & 0 deletions package-sets/top-level/matrix-icons/rooms/kde/kde.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions package-sets/top-level/matrix-icons/rooms/nixos-on-arm/icon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"type": "standard",
"colours": {
"background": 1,
"border": 6,
"text": 4
},
"contents": {
"style": "text",
"text": "arm"
}
}
12 changes: 12 additions & 0 deletions package-sets/top-level/matrix-icons/rooms/security/icon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"type": "standard",
"colours": {
"background": 7,
"border": "#FF0000",
"text": "#991111"
},
"contents": {
"style": "text",
"text": "#@!%"
}
}
10 changes: 10 additions & 0 deletions package-sets/top-level/matrix-icons/rooms/users/icon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"type": "main",
"colours": {
"background": 1,
"border": 2
},
"contents": {
"image": "nixos-logomark-default-gradient-minimal"
}
}