modaq
Version:
Quiz Bowl Reader using TypeScript, React, and MobX
207 lines • 11 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FontDialog = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = __importDefault(require("react"));
const mobx_react_lite_1 = require("mobx-react-lite");
const react_2 = require("@fluentui/react");
const FontDialogController = __importStar(require("./FontDialogController"));
require("../../state/AppState");
const StateContext_1 = require("../../contexts/StateContext");
require("../../state/FontDialogState");
const ModalVisibilityStatus_1 = require("../../state/ModalVisibilityStatus");
const ModalDialog_1 = require("./ModalDialog");
const defaultFont = "Segoe UI";
const knownFonts = [
"Arial",
"Century Schoolbook L",
"Consolas",
"Courier New",
"Garamond",
"Georgia",
"Helvetica",
"Liberation Serif",
"Palatino",
"serif",
"Segoe UI",
"Tahoma",
"Times New Roman",
"Verdana",
];
const minimumFontSize = 12;
const maximumFontSize = 40;
const stackTokens = { childrenGap: 10 };
exports.FontDialog = mobx_react_lite_1.observer(function FontDialog() {
return (jsx_runtime_1.jsxs(ModalDialog_1.ModalDialog, Object.assign({ title: "Font", visibilityStatus: ModalVisibilityStatus_1.ModalVisibilityStatus.Font, maxWidth: "40vw", onDismiss: FontDialogController.cancel }, { children: [jsx_runtime_1.jsx(FontDialogBody, {}, void 0),
jsx_runtime_1.jsxs(react_2.DialogFooter, { children: [jsx_runtime_1.jsx(react_2.PrimaryButton, { text: "OK", onClick: FontDialogController.update }, void 0),
jsx_runtime_1.jsx(react_2.DefaultButton, { text: "Cancel", onClick: FontDialogController.cancel }, void 0)] }, void 0)] }), void 0));
});
// If we really want flexibility for text/pronunciation guide colors we can use a ColorPicker, but it takes up a lot of
// space and users realistically won't use most of the colors
const FontDialogBody = mobx_react_lite_1.observer(function FontDialogBody() {
var _a, _b, _c, _d, _e;
const [fonts] = react_1.default.useState(getAvailableFonts(knownFonts));
const appState = react_1.default.useContext(StateContext_1.StateContext);
const dialogState = appState.uiState.dialogState.fontDialog;
if (dialogState == undefined) {
return jsx_runtime_1.jsx(jsx_runtime_1.Fragment, {}, void 0);
}
const value = ((_a = dialogState.fontSize) !== null && _a !== void 0 ? _a : appState.uiState.questionFontSize).toString();
let fontSelected = false;
const fontOptions = fonts.map((font) => {
// fontFamily has several fonts, but the one we choose should be the primary font, so look for that
const selected = dialogState.fontFamily
? dialogState.fontFamily.startsWith(font)
: appState.uiState.fontFamily.startsWith(font);
fontSelected = fontSelected || selected;
return {
key: font,
text: font,
selected,
};
});
if (!fontSelected && fontOptions.length > 0) {
fontOptions[0].selected = true;
}
const blackTextCheckbox = (jsx_runtime_1.jsx(react_2.Checkbox, { label: "Use pure black for text", onChange: (ev, checked) => {
// Dark mode already uses pure white
if (checked === true && !appState.uiState.useDarkMode) {
FontDialogController.changeTextColor("black");
}
else {
FontDialogController.changeTextColor(undefined);
}
}, checked: dialogState.textColor === "black", disabled: appState.uiState.useDarkMode }, void 0));
const textColor = dialogState.textColor;
const pronunciationGuideOptions = [
{
key: "default",
text: "Default",
data: "#777777",
// There are cases where the color isn't set yet, so undefined and 777777 should match with this
selected: dialogState.pronunciationGuideColor == undefined,
},
{
key: "burgundy",
text: "Burgundy",
data: "#770077",
},
{
key: "black",
text: "Black",
data: "#000000",
},
{
key: "darkGray",
text: "Dark Gray",
data: "#555555",
},
{
key: "lightGray",
text: "Light Gray",
data: "#888888",
},
{
key: "purple",
text: "Purple",
data: "#6666FF",
},
{
key: "teal",
text: "Teal",
data: "#007777",
},
];
for (const option of pronunciationGuideOptions) {
if (dialogState.pronunciationGuideColor === option.data) {
option.selected = true;
}
}
const pronunciationGuideDropdown = (jsx_runtime_1.jsx(react_2.Dropdown, { label: "Pronunciation guide color", options: pronunciationGuideOptions, onChange: (ev, option) => {
FontDialogController.changePronunciationGuideColor(option === null || option === void 0 ? void 0 : option.data);
}, onRenderItem: (props, defaultRender) => {
var _a;
if (props == undefined || defaultRender == undefined) {
return jsx_runtime_1.jsx(jsx_runtime_1.Fragment, {}, void 0);
}
const elements = defaultRender(props);
return (jsx_runtime_1.jsxs(react_2.Stack, Object.assign({ horizontal: true }, { children: [jsx_runtime_1.jsx(react_2.StackItem, { children: jsx_runtime_1.jsx("div", { style: {
backgroundColor: (_a = props === null || props === void 0 ? void 0 : props.data) !== null && _a !== void 0 ? _a : dialogState.textColor,
width: 36,
height: "100%",
} }, `block_${props.key}`) }, void 0),
jsx_runtime_1.jsx(react_2.StackItem, { children: elements }, void 0)] }), void 0));
} }, void 0));
return (jsx_runtime_1.jsxs(react_2.Stack, Object.assign({ tokens: stackTokens }, { children: [jsx_runtime_1.jsx(react_2.StackItem, { children: jsx_runtime_1.jsx(react_2.Dropdown, { label: "Font", options: fontOptions, onRenderOption: (props, defaultRender) => {
if (props == undefined || defaultRender == undefined) {
return jsx_runtime_1.jsx(jsx_runtime_1.Fragment, {}, void 0);
}
// Fall back to the default UI if it's not loaded in the system
return (jsx_runtime_1.jsx(react_2.Label, Object.assign({ styles: { root: { fontFamily: props.text + ", " + defaultFont } } }, { children: props.text }), props.key));
}, onChange: (event, option) => {
FontDialogController.changeFontFamily(option === null || option === void 0 ? void 0 : option.text);
} }, void 0) }, void 0),
jsx_runtime_1.jsx(react_2.StackItem, { children: jsx_runtime_1.jsx(react_2.SpinButton, { label: "Font size", onChange: changeFontSize, value: value, min: minimumFontSize, max: maximumFontSize, step: 1, incrementButtonAriaLabel: "Increase font size by 1", decrementButtonAriaLabel: "Decrease font size by 1" }, void 0) }, void 0),
jsx_runtime_1.jsx(react_2.StackItem, { children: pronunciationGuideDropdown }, void 0),
jsx_runtime_1.jsx(react_2.StackItem, { children: blackTextCheckbox }, void 0),
jsx_runtime_1.jsxs(react_2.StackItem, { children: [jsx_runtime_1.jsx("span", Object.assign({ style: {
fontFamily: (_b = dialogState.fontFamily) !== null && _b !== void 0 ? _b : appState.uiState.fontFamily,
fontSize: (_c = dialogState.fontSize) !== null && _c !== void 0 ? _c : appState.uiState.questionFontSize,
color: textColor,
} }, { children: "Sample text" }), void 0),
jsx_runtime_1.jsxs("span", Object.assign({ style: {
fontFamily: (_d = dialogState.fontFamily) !== null && _d !== void 0 ? _d : appState.uiState.fontFamily,
fontSize: (_e = dialogState.fontSize) !== null && _e !== void 0 ? _e : appState.uiState.questionFontSize,
color: dialogState.pronunciationGuideColor,
} }, { children: [" ", "(text)"] }), void 0)] }, void 0)] }), void 0));
});
function changeFontSize(event, newValue) {
if (newValue == undefined) {
return;
}
const size = Number.parseInt(newValue, 10);
if (!isNaN(size)) {
FontDialogController.changePendingSize(newValue);
}
}
// Returns only the fonts that don't fallback to the system default
// Based off of https://www.samclarke.com/javascript-is-font-available/
function getAvailableFonts(fonts) {
// This creates an element with a large string outside of the view of the browser
const container = document.createElement("span");
container.innerHTML = Array(100).join("wi");
container.style.cssText = ["position:absolute", "width:auto", "font-size:128px", "left:-99999px"].join(" !important;");
document.body.append(container);
// We're never using a fantasy font like Papyrus, so check if we use the fallback font
container.style.fontFamily = "fantasy";
const defaultFontWidth = container.clientWidth;
const availableFonts = fonts.filter((font) => {
container.style.fontFamily = `${font}, fantasy`;
return container.clientWidth !== defaultFontWidth;
});
document.body.removeChild(container);
return availableFonts;
}
//# sourceMappingURL=FontDialog.js.map