too lazy to think of a message, so enjoy this pointless text. Good luck future me...
All checks were successful
Test action / Print hello world (push) Successful in 8m32s
All checks were successful
Test action / Print hello world (push) Successful in 8m32s
This commit is contained in:
parent
e7b0307690
commit
28fdba8b00
15 changed files with 3868 additions and 2785 deletions
76
flake.nix
76
flake.nix
|
|
@ -1,39 +1,39 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
|
||||
|
||||
flake-parts = {
|
||||
url = "github:hercules-ci/flake-parts";
|
||||
inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
bun2nix = {
|
||||
url = "github:baileyluTCD/bun2nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = inputs@{ flake-parts, ... }: flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"aarch64-darwin"
|
||||
"x86_64-darwin"
|
||||
];
|
||||
|
||||
imports = [
|
||||
./nix/devShells/flake-module.nix
|
||||
./nix/packages/flake-module.nix
|
||||
./nix/modules/flake-module.nix
|
||||
];
|
||||
|
||||
perSystem = { lib, self', ... }: {
|
||||
checks =
|
||||
let
|
||||
packages = lib.mapAttrs' (n: lib.nameValuePair "package-${n}") self'.packages;
|
||||
devShells = lib.mapAttrs' (n: lib.nameValuePair "devShell-${n}") self'.devShells;
|
||||
in
|
||||
packages // devShells;
|
||||
};
|
||||
};
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
|
||||
|
||||
flake-parts = {
|
||||
url = "github:hercules-ci/flake-parts";
|
||||
inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
bun2nix = {
|
||||
url = "github:baileyluTCD/bun2nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = inputs@{ flake-parts, ... }: flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"aarch64-darwin"
|
||||
"x86_64-darwin"
|
||||
];
|
||||
|
||||
imports = [
|
||||
./nix/devShells/flake-module.nix
|
||||
./nix/packages/flake-module.nix
|
||||
./nix/modules/flake-module.nix
|
||||
];
|
||||
|
||||
perSystem = { lib, self', ... }: {
|
||||
checks =
|
||||
let
|
||||
packages = lib.mapAttrs' (n: lib.nameValuePair "package-${n}") self'.packages;
|
||||
devShells = lib.mapAttrs' (n: lib.nameValuePair "devShell-${n}") self'.devShells;
|
||||
in
|
||||
packages // devShells;
|
||||
};
|
||||
};
|
||||
}
|
||||
10
justfile
10
justfile
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
|
||||
push:
|
||||
git add .
|
||||
git commit -m 'too lazy to think of a message, so enjoy this pointless text. Good luck future me...'
|
||||
|
||||
|
||||
push:
|
||||
git add .
|
||||
git commit -m 'too lazy to think of a message, so enjoy this pointless text. Good luck future me...'
|
||||
git push
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
{ inputs, ... }:
|
||||
{
|
||||
perSystem = { pkgs, system, ... }: {
|
||||
devShells.default = pkgs.mkShellNoCC {
|
||||
nativeBuildInputs = with pkgs; [
|
||||
bun
|
||||
inputs.bun2nix.packages.${system}.default
|
||||
];
|
||||
};
|
||||
};
|
||||
{ inputs, ... }:
|
||||
{
|
||||
perSystem = { pkgs, system, ... }: {
|
||||
devShells.default = pkgs.mkShellNoCC {
|
||||
nativeBuildInputs = with pkgs; [
|
||||
bun
|
||||
inputs.bun2nix.packages.${system}.default
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,142 +1,144 @@
|
|||
{ self, ... }:
|
||||
{
|
||||
flake.nixosModules.default =
|
||||
nixos@{ config, pkgs, lib, utils, ... }:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkPackageOption mkOption mkIf types;
|
||||
|
||||
format = pkgs.formats.json {};
|
||||
|
||||
cfg = config.services.amarth-customer-portal;
|
||||
in
|
||||
{
|
||||
options.services.amarth-customer-portal = {
|
||||
enable = mkEnableOption "Enable Amarth cloud's customer portal.";
|
||||
|
||||
package = mkPackageOption self.packages.${pkgs.hostPlatform.system} "amarth-customer-portal" {};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = "true";
|
||||
description = ''
|
||||
Open the configured port in the firewall.
|
||||
'';
|
||||
};
|
||||
|
||||
user = lib.mkOption {
|
||||
type = types.str;
|
||||
default = "amarth";
|
||||
description = ''
|
||||
User account under which FileBrowser runs.
|
||||
'';
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
type = types.str;
|
||||
default = "amarth";
|
||||
description = ''
|
||||
Group under which FileBrowser runs.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
default = {};
|
||||
description = ''
|
||||
'';
|
||||
type = types.submodule {
|
||||
freeformType = format.type;
|
||||
|
||||
options = {
|
||||
address = mkOption {
|
||||
default = "localhost";
|
||||
description = ''
|
||||
The address to listen on.
|
||||
'';
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 8080;
|
||||
description = ''
|
||||
Which port to run the portal on.
|
||||
'';
|
||||
};
|
||||
|
||||
dataDir = lib.mkOption {
|
||||
default = "/var/lib/amarth/customer-portal";
|
||||
description = ''
|
||||
Directory where the portal persists files.
|
||||
'';
|
||||
type = types.path;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd = {
|
||||
services.amarthCustomerPortal = {
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
description = "Amarth cloud's customer portal";
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = utils.escapeSystemdExecArgs [
|
||||
(lib.getExe cfg.package)
|
||||
"--config"
|
||||
(format.generate "config.json" cfg.settings)
|
||||
];
|
||||
|
||||
StateDirectory = "amarth-customer-portal";
|
||||
CacheDirectory = "amarth-customer-portal";
|
||||
WorkingDirectory = cfg.settings.dataDir;
|
||||
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
UMask = "0077";
|
||||
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectControlGroups = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
LockPersonality = true;
|
||||
RestrictAddressFamilies = [
|
||||
"AF_UNIX"
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
];
|
||||
DevicePolicy = "closed";
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
};
|
||||
};
|
||||
|
||||
tmpfiles.settings.amarth-customer-portal = {
|
||||
"${cfg.settings.dataDir}".d = {
|
||||
inherit (cfg) user group;
|
||||
mode = "0700";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
users = mkIf (cfg.user == "amarth") {
|
||||
amarth = { inherit (cfg) group; isSystemUser = true; };
|
||||
};
|
||||
|
||||
groups = mkIf (cfg.group == "amarth") {
|
||||
amarth = {};
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.port ];
|
||||
};
|
||||
};
|
||||
{ self, ... }:
|
||||
{
|
||||
flake.nixosModules.default =
|
||||
nixos@{ config, pkgs, lib, utils, ... }:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkPackageOption mkOption mkIf types;
|
||||
|
||||
format = pkgs.formats.json {};
|
||||
|
||||
cfg = config.services.amarth-customer-portal;
|
||||
in
|
||||
{
|
||||
options.services.amarth-customer-portal = {
|
||||
enable = mkEnableOption "Enable Amarth cloud's customer portal.";
|
||||
|
||||
package = mkPackageOption self.packages.${pkgs.hostPlatform.system} "amarth-customer-portal" {};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = "true";
|
||||
description = ''
|
||||
Open the configured port in the firewall.
|
||||
'';
|
||||
};
|
||||
|
||||
user = lib.mkOption {
|
||||
type = types.str;
|
||||
default = "amarth";
|
||||
description = ''
|
||||
User account under which FileBrowser runs.
|
||||
'';
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
type = types.str;
|
||||
default = "amarth";
|
||||
description = ''
|
||||
Group under which FileBrowser runs.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
default = {};
|
||||
description = ''
|
||||
'';
|
||||
type = types.submodule {
|
||||
freeformType = format.type;
|
||||
|
||||
options = {
|
||||
address = mkOption {
|
||||
default = "localhost";
|
||||
description = ''
|
||||
The address to listen on.
|
||||
'';
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 8080;
|
||||
description = ''
|
||||
Which port to run the portal on.
|
||||
'';
|
||||
};
|
||||
|
||||
dataDir = lib.mkOption {
|
||||
default = "/var/lib/amarth/customer-portal";
|
||||
description = ''
|
||||
Directory where the portal persists files.
|
||||
'';
|
||||
type = types.path;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd = {
|
||||
services.amarthCustomerPortal = {
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
description = "Amarth cloud's customer portal";
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = utils.escapeSystemdExecArgs [
|
||||
(lib.getExe cfg.bun)
|
||||
"run"
|
||||
"start"
|
||||
"--config"
|
||||
(format.generate "config.json" cfg.settings)
|
||||
];
|
||||
|
||||
StateDirectory = "amarth-customer-portal";
|
||||
CacheDirectory = "amarth-customer-portal";
|
||||
WorkingDirectory = cfg.settings.dataDir;
|
||||
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
UMask = "0077";
|
||||
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectControlGroups = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
LockPersonality = true;
|
||||
RestrictAddressFamilies = [
|
||||
"AF_UNIX"
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
];
|
||||
DevicePolicy = "closed";
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
};
|
||||
};
|
||||
|
||||
tmpfiles.settings.amarth-customer-portal = {
|
||||
"${cfg.settings.dataDir}".d = {
|
||||
inherit (cfg) user group;
|
||||
mode = "0700";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
users = mkIf (cfg.user == "amarth") {
|
||||
amarth = { inherit (cfg) group; isSystemUser = true; };
|
||||
};
|
||||
|
||||
groups = mkIf (cfg.group == "amarth") {
|
||||
amarth = {};
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.port ];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
{ ... }:
|
||||
{
|
||||
imports =
|
||||
let
|
||||
# Get all subdirectories in the current directory
|
||||
dirContents = builtins.readDir ./.;
|
||||
|
||||
# Filter to include only directories that have a flake-module.nix file
|
||||
# and exclude special directories like 'result'
|
||||
validModuleDirs = builtins.filter (
|
||||
name:
|
||||
name != "result"
|
||||
&& dirContents.${name} == "directory"
|
||||
&& builtins.pathExists (./. + "/${name}/flake-module.nix")
|
||||
) (builtins.attrNames dirContents);
|
||||
|
||||
# Create import paths for each valid directory
|
||||
imports = map (name: ./. + "/${name}/flake-module.nix") validModuleDirs;
|
||||
in
|
||||
imports;
|
||||
}
|
||||
{ ... }:
|
||||
{
|
||||
imports =
|
||||
let
|
||||
# Get all subdirectories in the current directory
|
||||
dirContents = builtins.readDir ./.;
|
||||
|
||||
# Filter to include only directories that have a flake-module.nix file
|
||||
# and exclude special directories like 'result'
|
||||
validModuleDirs = builtins.filter (
|
||||
name:
|
||||
name != "result"
|
||||
&& dirContents.${name} == "directory"
|
||||
&& builtins.pathExists (./. + "/${name}/flake-module.nix")
|
||||
) (builtins.attrNames dirContents);
|
||||
|
||||
# Create import paths for each valid directory
|
||||
imports = map (name: ./. + "/${name}/flake-module.nix") validModuleDirs;
|
||||
in
|
||||
imports;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
export BETTER_AUTH_SECRET='8&!3$!^U!&56qvSydEJ^E$cr^GSBWWFmbHJCLJ@w7vRWm7!R5b$DSoCmY$GW7HEF'
|
||||
export SESSION_SECRET='jJBqeVMvQe52HqLYWDunLEKbkkC9JqCrgP92nV5j2dC99eZWCtK9H2NrASH8AbxF'
|
||||
|
||||
bun run build --bun
|
||||
|
||||
|
|
|
|||
942
src/app.css
942
src/app.css
|
|
@ -1,471 +1,471 @@
|
|||
@layer reset, base, tokens, recipes, utilities;
|
||||
|
||||
@import "open-props/style" layer(tokens);
|
||||
@import "open-props/normalize" layer(reset);
|
||||
@import "open-props/durations" layer(base);
|
||||
|
||||
@import "open-props/theme.light.switch.min.css" layer(tokens);
|
||||
@import "open-props/theme.dark.switch.min.css" layer(tokens);
|
||||
|
||||
@layer base {
|
||||
html {
|
||||
display: grid;
|
||||
grid: 100% / 100%;
|
||||
inline-size: 100%;
|
||||
block-size: 100%;
|
||||
overflow: clip;
|
||||
|
||||
/* font-size: clamp(1rem, -0.875rem + 8.333vw, 3.5rem); */
|
||||
|
||||
& > body {
|
||||
display: grid;
|
||||
grid: 100% / 100%;
|
||||
inline-size: 100%;
|
||||
block-size: 100%;
|
||||
contain: layout style paint;
|
||||
|
||||
margin: 0;
|
||||
font-family: sans-serif;
|
||||
|
||||
overflow: clip;
|
||||
background-color: var(--surface-3);
|
||||
color: var(--text-2);
|
||||
accent-color: var(--primary-500);
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 1px solid var(--info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@layer reset {
|
||||
@property --sibling-index {
|
||||
syntax: "<integer>";
|
||||
inherits: false;
|
||||
initial-value: 1;
|
||||
}
|
||||
|
||||
@property --sibling-count {
|
||||
syntax: "<integer>";
|
||||
inherits: false;
|
||||
initial-value: 0;
|
||||
}
|
||||
|
||||
:nth-child(1) {
|
||||
--sibling-index: 1;
|
||||
}
|
||||
|
||||
:nth-child(2) {
|
||||
--sibling-index: 2;
|
||||
}
|
||||
|
||||
:nth-child(3) {
|
||||
--sibling-index: 3;
|
||||
}
|
||||
|
||||
:nth-child(4) {
|
||||
--sibling-index: 4;
|
||||
}
|
||||
|
||||
:nth-child(5) {
|
||||
--sibling-index: 5;
|
||||
}
|
||||
|
||||
:nth-child(6) {
|
||||
--sibling-index: 6;
|
||||
}
|
||||
|
||||
:nth-child(7) {
|
||||
--sibling-index: 7;
|
||||
}
|
||||
|
||||
:nth-child(8) {
|
||||
--sibling-index: 8;
|
||||
}
|
||||
|
||||
:nth-child(9) {
|
||||
--sibling-index: 9;
|
||||
}
|
||||
|
||||
:nth-child(10) {
|
||||
--sibling-index: 10;
|
||||
}
|
||||
:nth-child(11) {
|
||||
--sibling-index: 11;
|
||||
}
|
||||
:nth-child(12) {
|
||||
--sibling-index: 12;
|
||||
}
|
||||
:nth-child(13) {
|
||||
--sibling-index: 13;
|
||||
}
|
||||
:nth-child(14) {
|
||||
--sibling-index: 14;
|
||||
}
|
||||
:nth-child(15) {
|
||||
--sibling-index: 15;
|
||||
}
|
||||
:nth-child(16) {
|
||||
--sibling-index: 16;
|
||||
}
|
||||
:nth-child(17) {
|
||||
--sibling-index: 17;
|
||||
}
|
||||
:nth-child(18) {
|
||||
--sibling-index: 18;
|
||||
}
|
||||
:nth-child(19) {
|
||||
--sibling-index: 19;
|
||||
}
|
||||
|
||||
:nth-child(20) {
|
||||
--sibling-index: 20;
|
||||
}
|
||||
:nth-child(21) {
|
||||
--sibling-index: 21;
|
||||
}
|
||||
:nth-child(22) {
|
||||
--sibling-index: 22;
|
||||
}
|
||||
:nth-child(23) {
|
||||
--sibling-index: 23;
|
||||
}
|
||||
:nth-child(24) {
|
||||
--sibling-index: 24;
|
||||
}
|
||||
:nth-child(25) {
|
||||
--sibling-index: 25;
|
||||
}
|
||||
:nth-child(26) {
|
||||
--sibling-index: 26;
|
||||
}
|
||||
:nth-child(27) {
|
||||
--sibling-index: 27;
|
||||
}
|
||||
:nth-child(28) {
|
||||
--sibling-index: 28;
|
||||
}
|
||||
:nth-child(29) {
|
||||
--sibling-index: 29;
|
||||
}
|
||||
|
||||
:nth-child(30) {
|
||||
--sibling-index: 30;
|
||||
}
|
||||
:nth-child(31) {
|
||||
--sibling-index: 31;
|
||||
}
|
||||
:nth-child(32) {
|
||||
--sibling-index: 32;
|
||||
}
|
||||
:nth-child(33) {
|
||||
--sibling-index: 33;
|
||||
}
|
||||
:nth-child(34) {
|
||||
--sibling-index: 34;
|
||||
}
|
||||
:nth-child(35) {
|
||||
--sibling-index: 35;
|
||||
}
|
||||
:nth-child(36) {
|
||||
--sibling-index: 36;
|
||||
}
|
||||
:nth-child(37) {
|
||||
--sibling-index: 37;
|
||||
}
|
||||
:nth-child(38) {
|
||||
--sibling-index: 38;
|
||||
}
|
||||
:nth-child(39) {
|
||||
--sibling-index: 39;
|
||||
}
|
||||
|
||||
:nth-child(40) {
|
||||
--sibling-index: 40;
|
||||
}
|
||||
:nth-child(41) {
|
||||
--sibling-index: 41;
|
||||
}
|
||||
:nth-child(42) {
|
||||
--sibling-index: 42;
|
||||
}
|
||||
:nth-child(43) {
|
||||
--sibling-index: 43;
|
||||
}
|
||||
:nth-child(44) {
|
||||
--sibling-index: 44;
|
||||
}
|
||||
:nth-child(45) {
|
||||
--sibling-index: 45;
|
||||
}
|
||||
:nth-child(46) {
|
||||
--sibling-index: 46;
|
||||
}
|
||||
:nth-child(47) {
|
||||
--sibling-index: 47;
|
||||
}
|
||||
:nth-child(48) {
|
||||
--sibling-index: 48;
|
||||
}
|
||||
:nth-child(49) {
|
||||
--sibling-index: 49;
|
||||
}
|
||||
|
||||
:nth-child(50) {
|
||||
--sibling-index: 50;
|
||||
}
|
||||
:nth-child(51) {
|
||||
--sibling-index: 51;
|
||||
}
|
||||
:nth-child(52) {
|
||||
--sibling-index: 52;
|
||||
}
|
||||
:nth-child(53) {
|
||||
--sibling-index: 53;
|
||||
}
|
||||
:nth-child(54) {
|
||||
--sibling-index: 54;
|
||||
}
|
||||
:nth-child(55) {
|
||||
--sibling-index: 55;
|
||||
}
|
||||
:nth-child(56) {
|
||||
--sibling-index: 56;
|
||||
}
|
||||
:nth-child(57) {
|
||||
--sibling-index: 57;
|
||||
}
|
||||
:nth-child(58) {
|
||||
--sibling-index: 58;
|
||||
}
|
||||
:nth-child(59) {
|
||||
--sibling-index: 59;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(1)) > * {
|
||||
--sibling-count: 1;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(2)) > * {
|
||||
--sibling-count: 2;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(3)) > * {
|
||||
--sibling-count: 3;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(4)) > * {
|
||||
--sibling-count: 4;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(5)) > * {
|
||||
--sibling-count: 5;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(6)) > * {
|
||||
--sibling-count: 6;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(7)) > * {
|
||||
--sibling-count: 7;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(8)) > * {
|
||||
--sibling-count: 8;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(9)) > * {
|
||||
--sibling-count: 9;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(10)) > * {
|
||||
--sibling-count: 10;
|
||||
}
|
||||
:has(> :last-child:nth-child(11)) > * {
|
||||
--sibling-count: 11;
|
||||
}
|
||||
:has(> :last-child:nth-child(12)) > * {
|
||||
--sibling-count: 12;
|
||||
}
|
||||
:has(> :last-child:nth-child(13)) > * {
|
||||
--sibling-count: 13;
|
||||
}
|
||||
:has(> :last-child:nth-child(14)) > * {
|
||||
--sibling-count: 14;
|
||||
}
|
||||
:has(> :last-child:nth-child(15)) > * {
|
||||
--sibling-count: 15;
|
||||
}
|
||||
:has(> :last-child:nth-child(16)) > * {
|
||||
--sibling-count: 16;
|
||||
}
|
||||
:has(> :last-child:nth-child(17)) > * {
|
||||
--sibling-count: 17;
|
||||
}
|
||||
:has(> :last-child:nth-child(18)) > * {
|
||||
--sibling-count: 18;
|
||||
}
|
||||
:has(> :last-child:nth-child(19)) > * {
|
||||
--sibling-count: 19;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(20)) > * {
|
||||
--sibling-count: 20;
|
||||
}
|
||||
:has(> :last-child:nth-child(21)) > * {
|
||||
--sibling-count: 21;
|
||||
}
|
||||
:has(> :last-child:nth-child(22)) > * {
|
||||
--sibling-count: 22;
|
||||
}
|
||||
:has(> :last-child:nth-child(23)) > * {
|
||||
--sibling-count: 23;
|
||||
}
|
||||
:has(> :last-child:nth-child(24)) > * {
|
||||
--sibling-count: 24;
|
||||
}
|
||||
:has(> :last-child:nth-child(25)) > * {
|
||||
--sibling-count: 25;
|
||||
}
|
||||
:has(> :last-child:nth-child(26)) > * {
|
||||
--sibling-count: 26;
|
||||
}
|
||||
:has(> :last-child:nth-child(27)) > * {
|
||||
--sibling-count: 27;
|
||||
}
|
||||
:has(> :last-child:nth-child(28)) > * {
|
||||
--sibling-count: 28;
|
||||
}
|
||||
:has(> :last-child:nth-child(29)) > * {
|
||||
--sibling-count: 29;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(30)) > * {
|
||||
--sibling-count: 30;
|
||||
}
|
||||
:has(> :last-child:nth-child(31)) > * {
|
||||
--sibling-count: 31;
|
||||
}
|
||||
:has(> :last-child:nth-child(32)) > * {
|
||||
--sibling-count: 32;
|
||||
}
|
||||
:has(> :last-child:nth-child(33)) > * {
|
||||
--sibling-count: 33;
|
||||
}
|
||||
:has(> :last-child:nth-child(34)) > * {
|
||||
--sibling-count: 34;
|
||||
}
|
||||
:has(> :last-child:nth-child(35)) > * {
|
||||
--sibling-count: 35;
|
||||
}
|
||||
:has(> :last-child:nth-child(36)) > * {
|
||||
--sibling-count: 36;
|
||||
}
|
||||
:has(> :last-child:nth-child(37)) > * {
|
||||
--sibling-count: 37;
|
||||
}
|
||||
:has(> :last-child:nth-child(38)) > * {
|
||||
--sibling-count: 38;
|
||||
}
|
||||
:has(> :last-child:nth-child(39)) > * {
|
||||
--sibling-count: 39;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(40)) > * {
|
||||
--sibling-count: 40;
|
||||
}
|
||||
:has(> :last-child:nth-child(41)) > * {
|
||||
--sibling-count: 41;
|
||||
}
|
||||
:has(> :last-child:nth-child(42)) > * {
|
||||
--sibling-count: 42;
|
||||
}
|
||||
:has(> :last-child:nth-child(43)) > * {
|
||||
--sibling-count: 43;
|
||||
}
|
||||
:has(> :last-child:nth-child(44)) > * {
|
||||
--sibling-count: 44;
|
||||
}
|
||||
:has(> :last-child:nth-child(45)) > * {
|
||||
--sibling-count: 45;
|
||||
}
|
||||
:has(> :last-child:nth-child(46)) > * {
|
||||
--sibling-count: 46;
|
||||
}
|
||||
:has(> :last-child:nth-child(47)) > * {
|
||||
--sibling-count: 47;
|
||||
}
|
||||
:has(> :last-child:nth-child(48)) > * {
|
||||
--sibling-count: 48;
|
||||
}
|
||||
:has(> :last-child:nth-child(49)) > * {
|
||||
--sibling-count: 49;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(50)) > * {
|
||||
--sibling-count: 50;
|
||||
}
|
||||
:has(> :last-child:nth-child(51)) > * {
|
||||
--sibling-count: 51;
|
||||
}
|
||||
:has(> :last-child:nth-child(52)) > * {
|
||||
--sibling-count: 52;
|
||||
}
|
||||
:has(> :last-child:nth-child(53)) > * {
|
||||
--sibling-count: 53;
|
||||
}
|
||||
:has(> :last-child:nth-child(54)) > * {
|
||||
--sibling-count: 54;
|
||||
}
|
||||
:has(> :last-child:nth-child(55)) > * {
|
||||
--sibling-count: 55;
|
||||
}
|
||||
:has(> :last-child:nth-child(56)) > * {
|
||||
--sibling-count: 56;
|
||||
}
|
||||
:has(> :last-child:nth-child(57)) > * {
|
||||
--sibling-count: 57;
|
||||
}
|
||||
:has(> :last-child:nth-child(58)) > * {
|
||||
--sibling-count: 58;
|
||||
}
|
||||
:has(> :last-child:nth-child(59)) > * {
|
||||
--sibling-count: 59;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(60)) > * {
|
||||
--sibling-count: 60;
|
||||
}
|
||||
:has(> :last-child:nth-child(61)) > * {
|
||||
--sibling-count: 61;
|
||||
}
|
||||
:has(> :last-child:nth-child(62)) > * {
|
||||
--sibling-count: 62;
|
||||
}
|
||||
:has(> :last-child:nth-child(63)) > * {
|
||||
--sibling-count: 63;
|
||||
}
|
||||
:has(> :last-child:nth-child(64)) > * {
|
||||
--sibling-count: 64;
|
||||
}
|
||||
:has(> :last-child:nth-child(65)) > * {
|
||||
--sibling-count: 65;
|
||||
}
|
||||
:has(> :last-child:nth-child(66)) > * {
|
||||
--sibling-count: 66;
|
||||
}
|
||||
:has(> :last-child:nth-child(67)) > * {
|
||||
--sibling-count: 67;
|
||||
}
|
||||
:has(> :last-child:nth-child(68)) > * {
|
||||
--sibling-count: 68;
|
||||
}
|
||||
:has(> :last-child:nth-child(69)) > * {
|
||||
--sibling-count: 69;
|
||||
}
|
||||
}
|
||||
@layer reset, base, tokens, recipes, utilities;
|
||||
|
||||
@import "open-props/style" layer(tokens);
|
||||
@import "open-props/normalize" layer(reset);
|
||||
@import "open-props/durations" layer(base);
|
||||
|
||||
@import "open-props/theme.light.switch.min.css" layer(tokens);
|
||||
@import "open-props/theme.dark.switch.min.css" layer(tokens);
|
||||
|
||||
@layer base {
|
||||
html {
|
||||
display: grid;
|
||||
grid: 100% / 100%;
|
||||
inline-size: 100%;
|
||||
block-size: 100%;
|
||||
overflow: clip;
|
||||
|
||||
/* font-size: clamp(1rem, -0.875rem + 8.333vw, 3.5rem); */
|
||||
|
||||
& > body {
|
||||
display: grid;
|
||||
grid: 100% / 100%;
|
||||
inline-size: 100%;
|
||||
block-size: 100%;
|
||||
contain: layout style paint;
|
||||
|
||||
margin: 0;
|
||||
font-family: sans-serif;
|
||||
|
||||
overflow: clip;
|
||||
background-color: var(--surface-3);
|
||||
color: var(--text-2);
|
||||
accent-color: var(--primary-500);
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 1px solid var(--info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@layer reset {
|
||||
@property --sibling-index {
|
||||
syntax: "<integer>";
|
||||
inherits: false;
|
||||
initial-value: 1;
|
||||
}
|
||||
|
||||
@property --sibling-count {
|
||||
syntax: "<integer>";
|
||||
inherits: false;
|
||||
initial-value: 0;
|
||||
}
|
||||
|
||||
:nth-child(1) {
|
||||
--sibling-index: 1;
|
||||
}
|
||||
|
||||
:nth-child(2) {
|
||||
--sibling-index: 2;
|
||||
}
|
||||
|
||||
:nth-child(3) {
|
||||
--sibling-index: 3;
|
||||
}
|
||||
|
||||
:nth-child(4) {
|
||||
--sibling-index: 4;
|
||||
}
|
||||
|
||||
:nth-child(5) {
|
||||
--sibling-index: 5;
|
||||
}
|
||||
|
||||
:nth-child(6) {
|
||||
--sibling-index: 6;
|
||||
}
|
||||
|
||||
:nth-child(7) {
|
||||
--sibling-index: 7;
|
||||
}
|
||||
|
||||
:nth-child(8) {
|
||||
--sibling-index: 8;
|
||||
}
|
||||
|
||||
:nth-child(9) {
|
||||
--sibling-index: 9;
|
||||
}
|
||||
|
||||
:nth-child(10) {
|
||||
--sibling-index: 10;
|
||||
}
|
||||
:nth-child(11) {
|
||||
--sibling-index: 11;
|
||||
}
|
||||
:nth-child(12) {
|
||||
--sibling-index: 12;
|
||||
}
|
||||
:nth-child(13) {
|
||||
--sibling-index: 13;
|
||||
}
|
||||
:nth-child(14) {
|
||||
--sibling-index: 14;
|
||||
}
|
||||
:nth-child(15) {
|
||||
--sibling-index: 15;
|
||||
}
|
||||
:nth-child(16) {
|
||||
--sibling-index: 16;
|
||||
}
|
||||
:nth-child(17) {
|
||||
--sibling-index: 17;
|
||||
}
|
||||
:nth-child(18) {
|
||||
--sibling-index: 18;
|
||||
}
|
||||
:nth-child(19) {
|
||||
--sibling-index: 19;
|
||||
}
|
||||
|
||||
:nth-child(20) {
|
||||
--sibling-index: 20;
|
||||
}
|
||||
:nth-child(21) {
|
||||
--sibling-index: 21;
|
||||
}
|
||||
:nth-child(22) {
|
||||
--sibling-index: 22;
|
||||
}
|
||||
:nth-child(23) {
|
||||
--sibling-index: 23;
|
||||
}
|
||||
:nth-child(24) {
|
||||
--sibling-index: 24;
|
||||
}
|
||||
:nth-child(25) {
|
||||
--sibling-index: 25;
|
||||
}
|
||||
:nth-child(26) {
|
||||
--sibling-index: 26;
|
||||
}
|
||||
:nth-child(27) {
|
||||
--sibling-index: 27;
|
||||
}
|
||||
:nth-child(28) {
|
||||
--sibling-index: 28;
|
||||
}
|
||||
:nth-child(29) {
|
||||
--sibling-index: 29;
|
||||
}
|
||||
|
||||
:nth-child(30) {
|
||||
--sibling-index: 30;
|
||||
}
|
||||
:nth-child(31) {
|
||||
--sibling-index: 31;
|
||||
}
|
||||
:nth-child(32) {
|
||||
--sibling-index: 32;
|
||||
}
|
||||
:nth-child(33) {
|
||||
--sibling-index: 33;
|
||||
}
|
||||
:nth-child(34) {
|
||||
--sibling-index: 34;
|
||||
}
|
||||
:nth-child(35) {
|
||||
--sibling-index: 35;
|
||||
}
|
||||
:nth-child(36) {
|
||||
--sibling-index: 36;
|
||||
}
|
||||
:nth-child(37) {
|
||||
--sibling-index: 37;
|
||||
}
|
||||
:nth-child(38) {
|
||||
--sibling-index: 38;
|
||||
}
|
||||
:nth-child(39) {
|
||||
--sibling-index: 39;
|
||||
}
|
||||
|
||||
:nth-child(40) {
|
||||
--sibling-index: 40;
|
||||
}
|
||||
:nth-child(41) {
|
||||
--sibling-index: 41;
|
||||
}
|
||||
:nth-child(42) {
|
||||
--sibling-index: 42;
|
||||
}
|
||||
:nth-child(43) {
|
||||
--sibling-index: 43;
|
||||
}
|
||||
:nth-child(44) {
|
||||
--sibling-index: 44;
|
||||
}
|
||||
:nth-child(45) {
|
||||
--sibling-index: 45;
|
||||
}
|
||||
:nth-child(46) {
|
||||
--sibling-index: 46;
|
||||
}
|
||||
:nth-child(47) {
|
||||
--sibling-index: 47;
|
||||
}
|
||||
:nth-child(48) {
|
||||
--sibling-index: 48;
|
||||
}
|
||||
:nth-child(49) {
|
||||
--sibling-index: 49;
|
||||
}
|
||||
|
||||
:nth-child(50) {
|
||||
--sibling-index: 50;
|
||||
}
|
||||
:nth-child(51) {
|
||||
--sibling-index: 51;
|
||||
}
|
||||
:nth-child(52) {
|
||||
--sibling-index: 52;
|
||||
}
|
||||
:nth-child(53) {
|
||||
--sibling-index: 53;
|
||||
}
|
||||
:nth-child(54) {
|
||||
--sibling-index: 54;
|
||||
}
|
||||
:nth-child(55) {
|
||||
--sibling-index: 55;
|
||||
}
|
||||
:nth-child(56) {
|
||||
--sibling-index: 56;
|
||||
}
|
||||
:nth-child(57) {
|
||||
--sibling-index: 57;
|
||||
}
|
||||
:nth-child(58) {
|
||||
--sibling-index: 58;
|
||||
}
|
||||
:nth-child(59) {
|
||||
--sibling-index: 59;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(1)) > * {
|
||||
--sibling-count: 1;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(2)) > * {
|
||||
--sibling-count: 2;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(3)) > * {
|
||||
--sibling-count: 3;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(4)) > * {
|
||||
--sibling-count: 4;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(5)) > * {
|
||||
--sibling-count: 5;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(6)) > * {
|
||||
--sibling-count: 6;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(7)) > * {
|
||||
--sibling-count: 7;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(8)) > * {
|
||||
--sibling-count: 8;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(9)) > * {
|
||||
--sibling-count: 9;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(10)) > * {
|
||||
--sibling-count: 10;
|
||||
}
|
||||
:has(> :last-child:nth-child(11)) > * {
|
||||
--sibling-count: 11;
|
||||
}
|
||||
:has(> :last-child:nth-child(12)) > * {
|
||||
--sibling-count: 12;
|
||||
}
|
||||
:has(> :last-child:nth-child(13)) > * {
|
||||
--sibling-count: 13;
|
||||
}
|
||||
:has(> :last-child:nth-child(14)) > * {
|
||||
--sibling-count: 14;
|
||||
}
|
||||
:has(> :last-child:nth-child(15)) > * {
|
||||
--sibling-count: 15;
|
||||
}
|
||||
:has(> :last-child:nth-child(16)) > * {
|
||||
--sibling-count: 16;
|
||||
}
|
||||
:has(> :last-child:nth-child(17)) > * {
|
||||
--sibling-count: 17;
|
||||
}
|
||||
:has(> :last-child:nth-child(18)) > * {
|
||||
--sibling-count: 18;
|
||||
}
|
||||
:has(> :last-child:nth-child(19)) > * {
|
||||
--sibling-count: 19;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(20)) > * {
|
||||
--sibling-count: 20;
|
||||
}
|
||||
:has(> :last-child:nth-child(21)) > * {
|
||||
--sibling-count: 21;
|
||||
}
|
||||
:has(> :last-child:nth-child(22)) > * {
|
||||
--sibling-count: 22;
|
||||
}
|
||||
:has(> :last-child:nth-child(23)) > * {
|
||||
--sibling-count: 23;
|
||||
}
|
||||
:has(> :last-child:nth-child(24)) > * {
|
||||
--sibling-count: 24;
|
||||
}
|
||||
:has(> :last-child:nth-child(25)) > * {
|
||||
--sibling-count: 25;
|
||||
}
|
||||
:has(> :last-child:nth-child(26)) > * {
|
||||
--sibling-count: 26;
|
||||
}
|
||||
:has(> :last-child:nth-child(27)) > * {
|
||||
--sibling-count: 27;
|
||||
}
|
||||
:has(> :last-child:nth-child(28)) > * {
|
||||
--sibling-count: 28;
|
||||
}
|
||||
:has(> :last-child:nth-child(29)) > * {
|
||||
--sibling-count: 29;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(30)) > * {
|
||||
--sibling-count: 30;
|
||||
}
|
||||
:has(> :last-child:nth-child(31)) > * {
|
||||
--sibling-count: 31;
|
||||
}
|
||||
:has(> :last-child:nth-child(32)) > * {
|
||||
--sibling-count: 32;
|
||||
}
|
||||
:has(> :last-child:nth-child(33)) > * {
|
||||
--sibling-count: 33;
|
||||
}
|
||||
:has(> :last-child:nth-child(34)) > * {
|
||||
--sibling-count: 34;
|
||||
}
|
||||
:has(> :last-child:nth-child(35)) > * {
|
||||
--sibling-count: 35;
|
||||
}
|
||||
:has(> :last-child:nth-child(36)) > * {
|
||||
--sibling-count: 36;
|
||||
}
|
||||
:has(> :last-child:nth-child(37)) > * {
|
||||
--sibling-count: 37;
|
||||
}
|
||||
:has(> :last-child:nth-child(38)) > * {
|
||||
--sibling-count: 38;
|
||||
}
|
||||
:has(> :last-child:nth-child(39)) > * {
|
||||
--sibling-count: 39;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(40)) > * {
|
||||
--sibling-count: 40;
|
||||
}
|
||||
:has(> :last-child:nth-child(41)) > * {
|
||||
--sibling-count: 41;
|
||||
}
|
||||
:has(> :last-child:nth-child(42)) > * {
|
||||
--sibling-count: 42;
|
||||
}
|
||||
:has(> :last-child:nth-child(43)) > * {
|
||||
--sibling-count: 43;
|
||||
}
|
||||
:has(> :last-child:nth-child(44)) > * {
|
||||
--sibling-count: 44;
|
||||
}
|
||||
:has(> :last-child:nth-child(45)) > * {
|
||||
--sibling-count: 45;
|
||||
}
|
||||
:has(> :last-child:nth-child(46)) > * {
|
||||
--sibling-count: 46;
|
||||
}
|
||||
:has(> :last-child:nth-child(47)) > * {
|
||||
--sibling-count: 47;
|
||||
}
|
||||
:has(> :last-child:nth-child(48)) > * {
|
||||
--sibling-count: 48;
|
||||
}
|
||||
:has(> :last-child:nth-child(49)) > * {
|
||||
--sibling-count: 49;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(50)) > * {
|
||||
--sibling-count: 50;
|
||||
}
|
||||
:has(> :last-child:nth-child(51)) > * {
|
||||
--sibling-count: 51;
|
||||
}
|
||||
:has(> :last-child:nth-child(52)) > * {
|
||||
--sibling-count: 52;
|
||||
}
|
||||
:has(> :last-child:nth-child(53)) > * {
|
||||
--sibling-count: 53;
|
||||
}
|
||||
:has(> :last-child:nth-child(54)) > * {
|
||||
--sibling-count: 54;
|
||||
}
|
||||
:has(> :last-child:nth-child(55)) > * {
|
||||
--sibling-count: 55;
|
||||
}
|
||||
:has(> :last-child:nth-child(56)) > * {
|
||||
--sibling-count: 56;
|
||||
}
|
||||
:has(> :last-child:nth-child(57)) > * {
|
||||
--sibling-count: 57;
|
||||
}
|
||||
:has(> :last-child:nth-child(58)) > * {
|
||||
--sibling-count: 58;
|
||||
}
|
||||
:has(> :last-child:nth-child(59)) > * {
|
||||
--sibling-count: 59;
|
||||
}
|
||||
|
||||
:has(> :last-child:nth-child(60)) > * {
|
||||
--sibling-count: 60;
|
||||
}
|
||||
:has(> :last-child:nth-child(61)) > * {
|
||||
--sibling-count: 61;
|
||||
}
|
||||
:has(> :last-child:nth-child(62)) > * {
|
||||
--sibling-count: 62;
|
||||
}
|
||||
:has(> :last-child:nth-child(63)) > * {
|
||||
--sibling-count: 63;
|
||||
}
|
||||
:has(> :last-child:nth-child(64)) > * {
|
||||
--sibling-count: 64;
|
||||
}
|
||||
:has(> :last-child:nth-child(65)) > * {
|
||||
--sibling-count: 65;
|
||||
}
|
||||
:has(> :last-child:nth-child(66)) > * {
|
||||
--sibling-count: 66;
|
||||
}
|
||||
:has(> :last-child:nth-child(67)) > * {
|
||||
--sibling-count: 67;
|
||||
}
|
||||
:has(> :last-child:nth-child(68)) > * {
|
||||
--sibling-count: 68;
|
||||
}
|
||||
:has(> :last-child:nth-child(69)) > * {
|
||||
--sibling-count: 69;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,35 @@
|
|||
import { Component, createSignal, onCleanup, onMount } from "solid-js";
|
||||
import { Entry } from "~/features/content";
|
||||
import css from "./details.module.css";
|
||||
|
||||
interface DetailsProps {
|
||||
entry: Entry;
|
||||
}
|
||||
|
||||
export const Details: Component<DetailsProps> = (props) => {
|
||||
const [header, setHeader] = createSignal<HTMLElement>();
|
||||
|
||||
onMount(() => {
|
||||
const observer = new ResizeObserver(([entry]) => {
|
||||
const { inlineSize, blockSize } = entry.contentBoxSize[0];
|
||||
(entry.target as HTMLElement).style.setProperty(
|
||||
"--ratio",
|
||||
String((blockSize * 0.2) / inlineSize)
|
||||
);
|
||||
});
|
||||
|
||||
observer.observe(header()!);
|
||||
|
||||
onCleanup(() => observer.disconnect());
|
||||
});
|
||||
|
||||
return (
|
||||
<div class={css.container}>
|
||||
<header ref={setHeader} class={css.header}>
|
||||
<img class={css.background} src={props.entry.image} />
|
||||
|
||||
<h1>{props.entry.title}</h1>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
import { Component, createSignal, onCleanup, onMount } from "solid-js";
|
||||
import { Entry } from "~/features/content";
|
||||
import css from "./details.module.css";
|
||||
|
||||
interface DetailsProps {
|
||||
entry: Entry;
|
||||
}
|
||||
|
||||
export const Details: Component<DetailsProps> = (props) => {
|
||||
const [header, setHeader] = createSignal<HTMLElement>();
|
||||
|
||||
onMount(() => {
|
||||
const observer = new ResizeObserver(([entry]) => {
|
||||
const { inlineSize, blockSize } = entry.contentBoxSize[0];
|
||||
(entry.target as HTMLElement).style.setProperty(
|
||||
"--ratio",
|
||||
String((blockSize * 0.2) / inlineSize)
|
||||
);
|
||||
});
|
||||
|
||||
observer.observe(header()!);
|
||||
|
||||
onCleanup(() => observer.disconnect());
|
||||
});
|
||||
|
||||
return (
|
||||
<div class={css.container}>
|
||||
<header ref={setHeader} class={css.header}>
|
||||
<img class={css.background} src={props.entry.image} />
|
||||
|
||||
<h1>{props.entry.title}</h1>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,88 +1,88 @@
|
|||
import {
|
||||
ContextProviderProps,
|
||||
createContextProvider,
|
||||
} from "@solid-primitives/context";
|
||||
import { action, createAsyncStore, query, useAction } from "@solidjs/router";
|
||||
import { createStore } from "solid-js/store";
|
||||
import { useSession } from "vinxi/http";
|
||||
|
||||
export enum ColorScheme {
|
||||
Auto = "light dark",
|
||||
Light = "light",
|
||||
Dark = "dark",
|
||||
}
|
||||
|
||||
export interface State {
|
||||
colorScheme: ColorScheme;
|
||||
hue: number;
|
||||
}
|
||||
|
||||
const getSession = async () => {
|
||||
"use server";
|
||||
|
||||
return useSession<State>({
|
||||
password: process.env.SESSION_SECRET!,
|
||||
});
|
||||
};
|
||||
|
||||
export const getState = query(async () => {
|
||||
"use server";
|
||||
|
||||
const session = await getSession();
|
||||
|
||||
if (Object.getOwnPropertyNames(session.data).length === 0) {
|
||||
await session.update({
|
||||
colorScheme: ColorScheme.Auto,
|
||||
hue: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return session.data;
|
||||
}, "color-scheme");
|
||||
|
||||
const setState = action(async (state: State) => {
|
||||
"use server";
|
||||
|
||||
const session = await getSession();
|
||||
await session.update((prev) => ({ ...prev, ...state }));
|
||||
}, "color-scheme");
|
||||
|
||||
interface ThemeContextType {
|
||||
readonly theme: State;
|
||||
setColorScheme(colorScheme: ColorScheme): void;
|
||||
setHue(colorScheme: number): void;
|
||||
}
|
||||
|
||||
const [ThemeContextProvider, useTheme] = createContextProvider<
|
||||
ThemeContextType,
|
||||
ContextProviderProps
|
||||
>(
|
||||
(props) => {
|
||||
const updateState = useAction(setState);
|
||||
const state = createAsyncStore(() => getState());
|
||||
|
||||
return {
|
||||
get theme() {
|
||||
return state.latest ?? { colorScheme: null };
|
||||
},
|
||||
|
||||
setColorScheme(colorScheme) {
|
||||
// updateState({ colorScheme, hue: state.latest!.hue });
|
||||
},
|
||||
setHue(hue) {
|
||||
// updateState({ hue, colorScheme: state.latest!.colorScheme });
|
||||
},
|
||||
};
|
||||
},
|
||||
{
|
||||
theme: {
|
||||
colorScheme: ColorScheme.Auto,
|
||||
hue: 180,
|
||||
},
|
||||
|
||||
setColorScheme(colorScheme) {},
|
||||
setHue(hue) {},
|
||||
},
|
||||
);
|
||||
|
||||
export { ThemeContextProvider, useTheme };
|
||||
import {
|
||||
ContextProviderProps,
|
||||
createContextProvider,
|
||||
} from "@solid-primitives/context";
|
||||
import { action, createAsyncStore, query, useAction } from "@solidjs/router";
|
||||
import { createStore } from "solid-js/store";
|
||||
import { useSession } from "vinxi/http";
|
||||
|
||||
export enum ColorScheme {
|
||||
Auto = "light dark",
|
||||
Light = "light",
|
||||
Dark = "dark",
|
||||
}
|
||||
|
||||
export interface State {
|
||||
colorScheme: ColorScheme;
|
||||
hue: number;
|
||||
}
|
||||
|
||||
const getSession = async () => {
|
||||
"use server";
|
||||
|
||||
return useSession<State>({
|
||||
password: process.env.SESSION_SECRET!,
|
||||
});
|
||||
};
|
||||
|
||||
export const getState = query(async () => {
|
||||
"use server";
|
||||
|
||||
const session = await getSession();
|
||||
|
||||
if (Object.getOwnPropertyNames(session.data).length === 0) {
|
||||
await session.update({
|
||||
colorScheme: ColorScheme.Auto,
|
||||
hue: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return session.data;
|
||||
}, "color-scheme");
|
||||
|
||||
const setState = action(async (state: State) => {
|
||||
"use server";
|
||||
|
||||
const session = await getSession();
|
||||
await session.update((prev) => ({ ...prev, ...state }));
|
||||
}, "color-scheme");
|
||||
|
||||
interface ThemeContextType {
|
||||
readonly theme: State;
|
||||
setColorScheme(colorScheme: ColorScheme): void;
|
||||
setHue(colorScheme: number): void;
|
||||
}
|
||||
|
||||
const [ThemeContextProvider, useTheme] = createContextProvider<
|
||||
ThemeContextType,
|
||||
ContextProviderProps
|
||||
>(
|
||||
(props) => {
|
||||
const updateState = useAction(setState);
|
||||
const state = createAsyncStore(() => getState());
|
||||
|
||||
return {
|
||||
get theme() {
|
||||
return state.latest ?? { colorScheme: null };
|
||||
},
|
||||
|
||||
setColorScheme(colorScheme) {
|
||||
// updateState({ colorScheme, hue: state.latest!.hue });
|
||||
},
|
||||
setHue(hue) {
|
||||
// updateState({ hue, colorScheme: state.latest!.colorScheme });
|
||||
},
|
||||
};
|
||||
},
|
||||
{
|
||||
theme: {
|
||||
colorScheme: ColorScheme.Auto,
|
||||
hue: 180,
|
||||
},
|
||||
|
||||
setColorScheme(colorScheme) {},
|
||||
setHue(hue) {},
|
||||
},
|
||||
);
|
||||
|
||||
export { ThemeContextProvider, useTheme };
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
|
||||
export { ThemeContextProvider, useTheme } from './context';
|
||||
|
||||
|
||||
export { ThemeContextProvider, useTheme } from './context';
|
||||
export { ColorSchemePicker } from './picker';
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
.picker {
|
||||
grid-template-columns: auto 1fr;
|
||||
}
|
||||
|
||||
.hue {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
align-items: center;
|
||||
.picker {
|
||||
grid-template-columns: auto 1fr;
|
||||
}
|
||||
|
||||
.hue {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
|
@ -1,69 +1,69 @@
|
|||
import {
|
||||
WiMoonAltFirstQuarter,
|
||||
WiMoonAltFull,
|
||||
WiMoonAltNew,
|
||||
} from "solid-icons/wi";
|
||||
import {
|
||||
Component,
|
||||
createEffect,
|
||||
For,
|
||||
Match,
|
||||
on,
|
||||
Setter,
|
||||
Switch,
|
||||
} from "solid-js";
|
||||
import { ColorScheme, useTheme } from "./context";
|
||||
import css from "./picker.module.css";
|
||||
import { Select } from "~/components/select";
|
||||
|
||||
const colorSchemes: Record<ColorScheme, keyof typeof ColorScheme> =
|
||||
Object.fromEntries(
|
||||
Object.entries(ColorScheme).map(([k, v]) => [v, k])
|
||||
) as any;
|
||||
|
||||
export const ColorSchemePicker: Component = (props) => {
|
||||
const themeContext = useTheme();
|
||||
|
||||
const setScheme: Setter<ColorScheme> = (next) => {
|
||||
if (typeof next === "function") {
|
||||
next = next();
|
||||
}
|
||||
|
||||
themeContext.setColorScheme(next);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<label aria-label="Color scheme picker">
|
||||
<Select
|
||||
id="color-scheme-picker"
|
||||
class={css.picker}
|
||||
value={themeContext.theme.colorScheme}
|
||||
setValue={setScheme}
|
||||
values={colorSchemes}
|
||||
>
|
||||
{(k, v) => (
|
||||
<>
|
||||
<Switch>
|
||||
<Match when={k === ColorScheme.Auto}>
|
||||
<WiMoonAltFirstQuarter />
|
||||
</Match>
|
||||
<Match when={k === ColorScheme.Light}>
|
||||
<WiMoonAltNew />
|
||||
</Match>
|
||||
<Match when={k === ColorScheme.Dark}>
|
||||
<WiMoonAltFull />
|
||||
</Match>
|
||||
</Switch>
|
||||
{v}
|
||||
</>
|
||||
)}
|
||||
</Select>
|
||||
</label>
|
||||
|
||||
{/* <label class={css.hue} aria-label="Hue slider">
|
||||
<input type="range" min="0" max="360" value={theme.hue} onInput={e => setHue(e.target.valueAsNumber)} />
|
||||
</label> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
import {
|
||||
WiMoonAltFirstQuarter,
|
||||
WiMoonAltFull,
|
||||
WiMoonAltNew,
|
||||
} from "solid-icons/wi";
|
||||
import {
|
||||
Component,
|
||||
createEffect,
|
||||
For,
|
||||
Match,
|
||||
on,
|
||||
Setter,
|
||||
Switch,
|
||||
} from "solid-js";
|
||||
import { ColorScheme, useTheme } from "./context";
|
||||
import css from "./picker.module.css";
|
||||
import { Select } from "~/components/select";
|
||||
|
||||
const colorSchemes: Record<ColorScheme, keyof typeof ColorScheme> =
|
||||
Object.fromEntries(
|
||||
Object.entries(ColorScheme).map(([k, v]) => [v, k])
|
||||
) as any;
|
||||
|
||||
export const ColorSchemePicker: Component = (props) => {
|
||||
const themeContext = useTheme();
|
||||
|
||||
const setScheme: Setter<ColorScheme> = (next) => {
|
||||
if (typeof next === "function") {
|
||||
next = next();
|
||||
}
|
||||
|
||||
themeContext.setColorScheme(next);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<label aria-label="Color scheme picker">
|
||||
<Select
|
||||
id="color-scheme-picker"
|
||||
class={css.picker}
|
||||
value={themeContext.theme.colorScheme}
|
||||
setValue={setScheme}
|
||||
values={colorSchemes}
|
||||
>
|
||||
{(k, v) => (
|
||||
<>
|
||||
<Switch>
|
||||
<Match when={k === ColorScheme.Auto}>
|
||||
<WiMoonAltFirstQuarter />
|
||||
</Match>
|
||||
<Match when={k === ColorScheme.Light}>
|
||||
<WiMoonAltNew />
|
||||
</Match>
|
||||
<Match when={k === ColorScheme.Dark}>
|
||||
<WiMoonAltFull />
|
||||
</Match>
|
||||
</Switch>
|
||||
{v}
|
||||
</>
|
||||
)}
|
||||
</Select>
|
||||
</label>
|
||||
|
||||
{/* <label class={css.hue} aria-label="Hue slider">
|
||||
<input type="range" min="0" max="360" value={theme.hue} onInput={e => setHue(e.target.valueAsNumber)} />
|
||||
</label> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,41 +1,41 @@
|
|||
import { Meta } from "@solidjs/meta";
|
||||
import { query, createAsync } from "@solidjs/router";
|
||||
import { ParentProps } from "solid-js";
|
||||
import { getRequestEvent } from "solid-js/web";
|
||||
import { auth } from "~/auth.server";
|
||||
import { Shell } from "~/features/shell";
|
||||
import { useTheme } from "~/features/theme";
|
||||
import { User } from "~/features/user";
|
||||
|
||||
const load = query(async (): Promise<User | undefined> => {
|
||||
"use server";
|
||||
|
||||
const session = await auth.api.getSession(getRequestEvent()!.request);
|
||||
|
||||
if (session === null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { username, name, email, image = null } = session.user;
|
||||
|
||||
return { username, name, email, image };
|
||||
}, "session");
|
||||
|
||||
export const route = {
|
||||
async preload() {
|
||||
return load();
|
||||
},
|
||||
};
|
||||
|
||||
export default function ShellPage(props: ParentProps) {
|
||||
const user = createAsync(() => load());
|
||||
const themeContext = useTheme();
|
||||
|
||||
return (
|
||||
<Shell user={user()}>
|
||||
<Meta name="color-scheme" content={themeContext.theme.colorScheme} />
|
||||
|
||||
{props.children}
|
||||
</Shell>
|
||||
);
|
||||
}
|
||||
import { Meta } from "@solidjs/meta";
|
||||
import { query, createAsync } from "@solidjs/router";
|
||||
import { ParentProps } from "solid-js";
|
||||
import { getRequestEvent } from "solid-js/web";
|
||||
import { auth } from "~/auth.server";
|
||||
import { Shell } from "~/features/shell";
|
||||
import { useTheme } from "~/features/theme";
|
||||
import { User } from "~/features/user";
|
||||
|
||||
const load = query(async (): Promise<User | undefined> => {
|
||||
"use server";
|
||||
|
||||
const session = await auth.api.getSession(getRequestEvent()!.request);
|
||||
|
||||
if (session === null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { username, name, email, image = null } = session.user;
|
||||
|
||||
return { username, name, email, image };
|
||||
}, "session");
|
||||
|
||||
export const route = {
|
||||
async preload() {
|
||||
return load();
|
||||
},
|
||||
};
|
||||
|
||||
export default function ShellPage(props: ParentProps) {
|
||||
const user = createAsync(() => load());
|
||||
const themeContext = useTheme();
|
||||
|
||||
return (
|
||||
<Shell user={user()}>
|
||||
<Meta name="color-scheme" content={themeContext.theme.colorScheme} />
|
||||
|
||||
{props.children}
|
||||
</Shell>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue