function listItems($list, items, callback) {
	const $items = [];

	// sort settings by text before rendering
	items.sort((acc, cur) => {
		if (!acc?.text || !cur?.text) return 0;
		return acc.text.localeCompare(cur.text);
	});
	items.forEach((item) => {
		const $setting = new Ref();
		const $settingName = new Ref();
		/**@type {HTMLDivElement} */
		const $item = (
			<div
				tabIndex={1}
				className={`list-item ${item.sake ? "sake" : ""}`}
				data-key={item.key}
				data-action="list-item"
			>
				<span
					className={`icon ${item.icon || "no-icon"}`}
					style={{ color: item.iconColor }}
				></span>
				<div ref={$setting} className="container">
					<div ref={$settingName} className="text">
						{item.text?.capitalize?.(0) ?? item.text}
					</div>
				</div>
			</div>
		);

		let $checkbox, $valueText;

		if (item.info) {
			$settingName.append(
				<span
					className="icon info info-button"
					data-action="info"
					onclick={() => {
						alert(strings.info, item.info);
					}}
				></span>,
			);
		}

		if (item.checkbox !== undefined || typeof item.value === "boolean") {
			$checkbox = Checkbox("", item.checkbox || item.value);
			$item.appendChild($checkbox);
			$item.style.paddingRight = "10px";
		} else if (item.value !== undefined) {
			$valueText = <small className="value"></small>;
			setValueText($valueText, item.value, item.valueText?.bind(item));
			$setting.append($valueText);
			setColor($item, item.value);
		}

		if (Number.isInteger(item.index)) {
			$items.splice(item.index, 0, $item);
		} else {
			$items.push($item);
		}

		$item.addEventListener("click", onclick);
	});

	$list.content = $items;

	/**
	 * Click handler for $list
	 * @this {HTMLElement}
	 * @param {MouseEvent} e
	 */
	async function onclick(e) {
		const $target = e.target;
		const { key } = e.target.dataset;

		const item = items.find((item) => item.key === key);
		if (!item) return;

		const {
			select: options,
			prompt: promptText,
			color: selectColor,
			checkbox,
			file,
			folder,
			link,
		} = item;
		const { text, value, valueText } = item;
		const { promptType, promptOptions } = item;

		const $valueText = $target.get(".value");
		const $checkbox = $target.get(".input-checkbox");
		let res;

		try {
			if (options) {
				res = await select(text, options, {
					default: value,
				});
			} else if (checkbox !== undefined) {
				$checkbox.toggle();
				res = $checkbox.checked;
			} else if (promptText) {
				res = await prompt(promptText, value, promptType, promptOptions);
				if (res === null) return;
			} else if (file || folder) {
				const mode = file ? "file" : "folder";
				const { url } = await FileBrowser(mode);
				res = url;
			} else if (selectColor) {
				res = await colorPicker(value);
			} else if (link) {
				system.openInBrowser(link);
				return;
			}
		} catch (error) {
			window.log("error", error);
		}

		item.value = res;
		setValueText($valueText, res, valueText?.bind(item));
		setColor($target, res);
		callback.call($target, key, item.value);
	}
}
Creates a list of settings
@param {HTMLUListElement} $list
@param {Array<ListItem>} items
@param {()=>void} callback called when setting is changed