Keyboard 104 layout

(c) PvH

by PhilQ

HTML

<div id="kb"></div>

SCSS

@function str-replace($string, $search, $replace: '') {
  $index: str-index($string, $search);
  
  @if $index {
    @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
  }
  
  @return $string;
}

*, ::before, ::after {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}

body {
	font-family: Source Sans Pro;
	font-size: 16px;
	background: #1f2227;
	color: #39464e;
	padding: 1rem;
}
$kw: 2.6rem;
$kh: 2.6rem;
$kg: 4px;


#kb {
	display: inline-flex;
	margin: 0 auto;
	line-height: 0;
	flex-direction: column;
	align-items: flex-start;
	gap: $kg;
}

.kb-row {
	display: inline-flex;
	width: auto;
	gap: $kg;
	
}
.kb-row-1 {
	margin-bottom: $kw * 0.5;
}

.kb-key {
	$pt: 3px;
	$pl: 5px;
	$pr: 5px;
	$pb: 7px;
	position: relative;
	display: flex;
	flex-direction: column;
	width: $kw;
	height: $kh;
	background: #ddd;
	padding: $pt $pr $pb $pl;
	border-radius: 5px;
	
	$ws: 1, 1.25, 1.5, 1.75, 2, 2.25, 2.75, 5.75;
	@each $w in $ws {
		&.key-#{str-replace(#{$w}, '.', '_')}x1 {
			width: calc(#{$kw * $w} + #{$kg * ($w - 1)});
		}
	}
	&.key-1x2 {
		height: calc(#{$kh * 2} + #{$kg});
		margin-bottom: calc(#{-$kh} - #{$kg});
	}
	
	&.key-sp_5 {
		margin-right: calc(#{0.5*$kw});
	}
	&.key-sp_75 {
		margin-right: calc(#{(2/3)*$kw} + #{(2/3)*$kg});
	}
	&.key-sp1_5 {
		margin-right: calc(#{1.5*$kw} + #{$kg});
	}
	&.key-sp4 {
		margin-right: calc(#{4*$kw} + #{3*$kg});
	}
	// $sps: 0.5, 0.75;
	// @each $s in $sps {
	// 	&.key-sp#{str-replace(#{$s}, '.', '_')} {
	// 		margin-right: $kw * $s;
	// 	}
	// }

	$padding: 0.25rem;
	> div {
		position: relative;
		z-index: 1;
		width: 100%;
		height: 100%;
		background: #fff;
		border-radius: 4px;

		> * {
			line-height: 1;
			font-weight: bold;
		}

		.c0 {
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
			font-size: 1rem;
			
			.kb-row-1 & {
				top: 0.5 * $padding;
				left: 0;
				right: 0;
				text-align:...

JavaScript

const keyconfig = {
	'G513': [
		[
			{ c_0: 'ESC', size: '1x1 sp_75' },
			{ c_0: 'F1', size: '1x1' },
			{ c_0: 'F2', size: '1x1' },
			{ c_0: 'F3', size: '1x1' },
			{ c_0: 'F4', size: '1x1 sp_75' },
			{ c_0: 'F5', size: '1x1' },
			{ c_0: 'F6', size: '1x1' },
			{ c_0: 'F7', size: '1x1' },
			{ c_0: 'F8', size: '1x1 sp_75' },
			{ c_0: 'F9', size: '1x1' },
			{ c_0: 'F10', size: '1x1' },
			{ c_0: 'F11', size: '1x1' },
			{ c_0: 'F12', size: '1x1 sp_5' },
			{ c_3: 'PRTSC', size: '1x1' },
			{ c_3: 'SCRLK', size: '1x1' },
			{ c_3: 'PAUSE', size: '1x1' },
		],
		[
			{ c_1: '`', c_2: '~', size: '1x1' },
			{ c_1: '1', c_2: '!', size: '1x1' },
			{ c_1: '2', c_2: '@', size: '1x1' },
			{ c_1: '3', c_2: '#', size: '1x1' },
			{ c_1: '4', c_2: '$', size: '1x1' },
			{ c_1: '5', c_2: '%', size: '1x1' },
 			{ c_1: '6', c_2: '^', size: '1x1' },
			{ c_1: '7', c_2: '&', size: '1x1' },
			{ c_1: '8', c_2: '*', size: '1x1' },
			{ c_1: '9', c_2: '(', size: '1x1' },
			{ c_1: '0', c_2: ')', size: '1x1' },
			{ c_1: '-', c_2: '_', size: '1x1' },
			{ c_1: '=', c_2: '+', size: '1x1' },
			{ c_0: '⇦', size: '2x1 sp_5' },
			{ c_3: 'INS', size: '1x1' },
			{ c_3: 'HOME', size: '1x1' },
			{ c_3: 'PG UP', size: '1x1 sp_5' },
			{ c_3: 'NUM', size: '1x1' },
			{ c_0: '/', size: '1x1' },
			{ c_0: '*', size: '1x1' },
			{ c_0: '-', size: '1x1' },
		],
		[
			{ c_3: 'TAB', size: '1_5x1' },
			{ c_0: 'Q', size: '1x1' },
			{ c_0: 'W', size: '1x1' },
			{ c_0: 'E', size: '1x1' },
			{ c_0: 'R', size: '1x1' },
			{ c_0: 'T', size: '1x1' },
			{ c_0: 'Y', size: '1x1' },
			{ c_0: 'U', size: '1x1' },
			{ c_0: 'I', size: '1x1' },
			{ c_0: 'O', size: '1x1' },
			{ c_0: 'P', size: '1x1' },
			{ c_1: '[', c_2: '{', size: '1x1' },
			{ c_1: ']', c_2: '}', size: '1x1' },
			{ c_0: '', size: '1_5x1 enter1 sp_5' },
			{ c_3: 'DEL', size: '1x1' },
			{ c_3: 'END', size: '1x1' },
			{ c_3: 'PG DN', size: '1x1 sp_5' },
			{ c_1: '7', c_2: 'HOME', size: '1x1' },
			{ c_1: '8', c_2: '🠩',...