mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-21 16:38:23 +01:00
add support for "Hack" font family (#309)
* testing hack font * updates to allow font to be variable * allow setting of font-family. get initial font family from electron (needed for loading) * add termfontfamily * update wave logos for README * hook up fontfamily setting, remove old dropdown active var * get app to reload on font change. reload fonts * on termfontsize change, bump render version as well
This commit is contained in:
parent
743d6d8622
commit
3f83b30b06
@ -1,3 +1,4 @@
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 h1:3/gm/JTX9bX8CpzTgIlrtYpB3EVBDxyg/GY/QdcIEZw=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
|
BIN
public/fonts/hack-bold.woff2
Normal file
BIN
public/fonts/hack-bold.woff2
Normal file
Binary file not shown.
BIN
public/fonts/hack-bolditalic.woff2
Normal file
BIN
public/fonts/hack-bolditalic.woff2
Normal file
Binary file not shown.
BIN
public/fonts/hack-italic.woff2
Normal file
BIN
public/fonts/hack-italic.woff2
Normal file
Binary file not shown.
BIN
public/fonts/hack-regular.woff2
Normal file
BIN
public/fonts/hack-regular.woff2
Normal file
Binary file not shown.
@ -1,12 +1,5 @@
|
||||
@import "./common/themes/themes.less";
|
||||
|
||||
@font-face {
|
||||
font-family: "Martian Mono";
|
||||
src: url("./assets/fonts/MartianMono-VariableFont_wdth,wght.ttf") format("truetype");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
:root {
|
||||
--fa-style-family: "Font Awesome 6 Sharp";
|
||||
}
|
||||
@ -98,7 +91,7 @@ body a {
|
||||
}
|
||||
|
||||
body code {
|
||||
font-family: @terminal-font;
|
||||
font-family: var(--termfontfamily);
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@ -312,7 +305,7 @@ a.a-block {
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: @terminal-font;
|
||||
font-family: var(--termfontfamily);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,8 +105,15 @@ class App extends React.Component<{}, {}> {
|
||||
if (dcWait) {
|
||||
setTimeout(() => this.updateDcWait(false), 0);
|
||||
}
|
||||
// used to force a full reload of the application
|
||||
let renderVersion = GlobalModel.renderVersion.get();
|
||||
return (
|
||||
<div id="main" className={"platform-" + platform} onContextMenu={this.handleContextMenu}>
|
||||
<div
|
||||
key={"version-" + renderVersion}
|
||||
id="main"
|
||||
className={"platform-" + platform}
|
||||
onContextMenu={this.handleContextMenu}
|
||||
>
|
||||
<div ref={this.mainContentRef} className="main-content">
|
||||
<MainSideBar parentRef={this.mainContentRef} clientData={clientData} />
|
||||
<ErrorBoundary>
|
||||
|
@ -26,6 +26,10 @@
|
||||
padding: 0 18px 0 30px;
|
||||
}
|
||||
|
||||
.wave-dropdown {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
// just marked these as important since we're keeping the
|
||||
// settings-field styles below this intact until we figure out what do with them
|
||||
.settings-field {
|
||||
|
@ -15,9 +15,6 @@ import "./clientsettings.less";
|
||||
|
||||
@mobxReact.observer
|
||||
class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
|
||||
fontSizeDropdownActive: OV<boolean> = mobx.observable.box(false, {
|
||||
name: "clientSettings-fontSizeDropdownActive",
|
||||
});
|
||||
errorMessage: OV<string> = mobx.observable.box(null, { name: "ClientSettings-errorMessage" });
|
||||
|
||||
@boundMethod
|
||||
@ -30,7 +27,6 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
@boundMethod
|
||||
handleChangeFontSize(fontSize: string): void {
|
||||
const newFontSize = Number(fontSize);
|
||||
this.fontSizeDropdownActive.set(false);
|
||||
if (GlobalModel.termFontSize.get() == newFontSize) {
|
||||
return;
|
||||
}
|
||||
@ -39,10 +35,12 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
togglefontSizeDropdown(): void {
|
||||
mobx.action(() => {
|
||||
this.fontSizeDropdownActive.set(!this.fontSizeDropdownActive.get());
|
||||
})();
|
||||
handleChangeFontFamily(fontFamily: string): void {
|
||||
if (GlobalModel.getTermFontFamily() == fontFamily) {
|
||||
return;
|
||||
}
|
||||
const prtn = GlobalCommandRunner.setTermFontFamily(fontFamily, false);
|
||||
commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
@ -75,6 +73,13 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
return availableFontSizes;
|
||||
}
|
||||
|
||||
getFontFamilies(): DropdownItem[] {
|
||||
const availableFontFamilies: DropdownItem[] = [];
|
||||
availableFontFamilies.push({ label: "JetBrains Mono", value: "JetBrains Mono" });
|
||||
availableFontFamilies.push({ label: "Hack", value: "Hack" });
|
||||
return availableFontFamilies;
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
inlineUpdateOpenAIModel(newModel: string): void {
|
||||
const prtn = GlobalCommandRunner.setClientOpenAISettings({ model: newModel });
|
||||
@ -140,6 +145,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
openAIOpts.maxtokens == null || openAIOpts.maxtokens == 0 ? 1000 : openAIOpts.maxtokens
|
||||
);
|
||||
const curFontSize = GlobalModel.termFontSize.get();
|
||||
const curFontFamily = GlobalModel.getTermFontFamily();
|
||||
|
||||
return (
|
||||
<div className={cn("view clientsettings-view")}>
|
||||
@ -161,6 +167,17 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Term Font Family</div>
|
||||
<div className="settings-input">
|
||||
<Dropdown
|
||||
className="font-size-dropdown"
|
||||
options={this.getFontFamilies()}
|
||||
defaultValue={curFontFamily}
|
||||
onChange={this.handleChangeFontFamily}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Client ID</div>
|
||||
<div className="settings-input">{cdata.clientid}</div>
|
||||
|
@ -10,14 +10,14 @@
|
||||
code {
|
||||
background-color: @markdown-highlight;
|
||||
color: @term-white;
|
||||
font-family: @terminal-font;
|
||||
font-family: var(--termfontfamily);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
code.inline {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
font-family: @terminal-font;
|
||||
font-family: var(--termfontfamily);
|
||||
}
|
||||
|
||||
.title {
|
||||
|
@ -1,7 +1,9 @@
|
||||
@import "@/common/themes/themes.less";
|
||||
|
||||
.term-prompt {
|
||||
font-weight: 300;
|
||||
font-weight: normal;
|
||||
font-family: var(--termfontfamily);
|
||||
|
||||
.icon {
|
||||
margin: 0 4px 0 2px;
|
||||
vertical-align: middle;
|
||||
|
@ -69,7 +69,6 @@
|
||||
|
||||
// @font-face declaration lives in app.less
|
||||
@fixed-font: "Martian Mono", sans-serif;
|
||||
@terminal-font: "JetBrains Mono", sans-serif;
|
||||
|
||||
@text-s1-font: "Martian Mono", sans-serif;
|
||||
|
||||
|
@ -492,7 +492,8 @@ class LineCmd extends React.Component<
|
||||
maxSize: screen.getMaxContentSize(),
|
||||
idealSize: screen.getIdealContentSize(),
|
||||
termOpts: cmd.getTermOpts(),
|
||||
termFontSize: GlobalModel.termFontSize.get(),
|
||||
termFontSize: GlobalModel.getTermFontSize(),
|
||||
termFontFamily: GlobalModel.getTermFontFamily(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@
|
||||
position: relative;
|
||||
|
||||
.cmd-rtnstate-label {
|
||||
font-family: @terminal-font;
|
||||
font-family: var(--termfontfamily);
|
||||
position: relative;
|
||||
font-size: 10px;
|
||||
z-index: 2;
|
||||
@ -145,7 +145,7 @@
|
||||
}
|
||||
|
||||
.cmd-rtnstate-diff {
|
||||
font-family: @terminal-font;
|
||||
font-family: var(--termfontfamily);
|
||||
color: @term-white;
|
||||
white-space: pre;
|
||||
margin-left: 10px;
|
||||
|
@ -137,7 +137,8 @@
|
||||
overflow-wrap: anywhere;
|
||||
border-color: transparent;
|
||||
border: none;
|
||||
font-family: @terminal-font;
|
||||
font-family: var(--termfontfamily);
|
||||
font-weight: normal;
|
||||
&.display-disabled {
|
||||
background-color: #444;
|
||||
}
|
||||
@ -229,7 +230,8 @@
|
||||
overflow-wrap: anywhere;
|
||||
border-color: transparent;
|
||||
border: none;
|
||||
font-family: @terminal-font;
|
||||
font-family: var(--termfontfamily);
|
||||
font-weight: normal;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 1;
|
||||
border-radius: 4px;
|
||||
|
@ -31,6 +31,7 @@ let oldConsoleLog = console.log;
|
||||
let wasActive = true;
|
||||
let wasInFg = true;
|
||||
let currentGlobalShortcut: string | null = null;
|
||||
let initialClientData: ClientDataType = null;
|
||||
|
||||
checkPromptMigrate();
|
||||
ensureDir(waveHome);
|
||||
@ -519,6 +520,11 @@ electron.ipcMain.on("wavesrv-status", (event) => {
|
||||
return;
|
||||
});
|
||||
|
||||
electron.ipcMain.on("get-initial-termfontfamily", (event) => {
|
||||
event.returnValue = initialClientData?.feopts?.termfontfamily;
|
||||
return;
|
||||
});
|
||||
|
||||
electron.ipcMain.on("restart-server", (event) => {
|
||||
if (waveSrvProc != null) {
|
||||
waveSrvProc.kill();
|
||||
@ -709,6 +715,7 @@ async function createMainWindowWrap() {
|
||||
let clientData: ClientDataType | null = null;
|
||||
try {
|
||||
clientData = await getClientDataPoll(1);
|
||||
initialClientData = clientData;
|
||||
} catch (e) {
|
||||
console.log("error getting wavesrv clientdata", e.toString());
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ contextBridge.exposeInMainWorld("api", {
|
||||
ipcRenderer.send("get-last-logs", numberOfLines);
|
||||
ipcRenderer.once("last-logs", (event, data) => callback(data));
|
||||
},
|
||||
getInitialTermFontFamily: () => ipcRenderer.sendSync("get-initial-termfontfamily"),
|
||||
restartWaveSrv: () => ipcRenderer.sendSync("restart-server"),
|
||||
reloadWindow: () => ipcRenderer.sendSync("reload-window"),
|
||||
reregisterGlobalShortcut: (shortcut) => ipcRenderer.sendSync("reregister-global-shortcut", shortcut),
|
||||
|
@ -9,13 +9,18 @@ import { App } from "@/app/app";
|
||||
import * as DOMPurify from "dompurify";
|
||||
import { loadFonts } from "./util/util";
|
||||
import * as textmeasure from "./util/textmeasure";
|
||||
import { getApi } from "@/models";
|
||||
|
||||
// @ts-ignore
|
||||
let VERSION = __WAVETERM_VERSION__;
|
||||
// @ts-ignore
|
||||
let BUILD = __WAVETERM_BUILD__;
|
||||
|
||||
loadFonts();
|
||||
let initialFontFamily = getApi().getInitialTermFontFamily();
|
||||
if (initialFontFamily == null) {
|
||||
initialFontFamily = "JetBrains Mono";
|
||||
}
|
||||
loadFonts(initialFontFamily);
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
let reactElem = React.createElement(App, null, null);
|
||||
@ -26,6 +31,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// put some items on the window for debugging
|
||||
(window as any).mobx = mobx;
|
||||
(window as any).sprintf = sprintf;
|
||||
(window as any).DOMPurify = DOMPurify;
|
||||
|
@ -353,6 +353,14 @@ class CommandRunner {
|
||||
return GlobalModel.submitCommand("client", "set", null, kwargs, interactive);
|
||||
}
|
||||
|
||||
setTermFontFamily(fontFamily: string, interactive: boolean): Promise<CommandRtnType> {
|
||||
let kwargs = {
|
||||
nohist: "1",
|
||||
termfontfamily: fontFamily,
|
||||
};
|
||||
return GlobalModel.submitCommand("client", "set", null, kwargs, interactive);
|
||||
}
|
||||
|
||||
setClientOpenAISettings(opts: { model?: string; apitoken?: string; maxtokens?: string }): Promise<CommandRtnType> {
|
||||
let kwargs = {
|
||||
nohist: "1",
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
genMergeSimpleData,
|
||||
isModKeyPress,
|
||||
isBlank,
|
||||
loadFonts,
|
||||
} from "@/util/util";
|
||||
import { WSControl } from "./ws";
|
||||
import { cmdStatusIsRunning } from "@/app/line/lineutil";
|
||||
@ -120,6 +121,10 @@ class Model {
|
||||
});
|
||||
packetSeqNum: number = 0;
|
||||
|
||||
renderVersion: OV<number> = mobx.observable.box(0, {
|
||||
name: "renderVersion",
|
||||
});
|
||||
|
||||
private constructor() {
|
||||
this.clientId = getApi().getId();
|
||||
this.isDev = getApi().getIsDev();
|
||||
@ -185,6 +190,12 @@ class Model {
|
||||
return (window as any).GlobalModel;
|
||||
}
|
||||
|
||||
bumpRenderVersion() {
|
||||
mobx.action(() => {
|
||||
this.renderVersion.set(this.renderVersion.get() + 1);
|
||||
})();
|
||||
}
|
||||
|
||||
getNextPacketSeqNum(): number {
|
||||
this.packetSeqNum++;
|
||||
return this.packetSeqNum;
|
||||
@ -314,6 +325,19 @@ class Model {
|
||||
return appconst.ProdServerEndpoint;
|
||||
}
|
||||
|
||||
getTermFontFamily(): string {
|
||||
let cdata = this.clientData.get();
|
||||
let ff = cdata?.feopts?.termfontfamily;
|
||||
if (ff == null) {
|
||||
ff = "JetBrains Mono, monospace";
|
||||
}
|
||||
return ff;
|
||||
}
|
||||
|
||||
getTermFontSize(): number {
|
||||
return this.termFontSize.get();
|
||||
}
|
||||
|
||||
setTermFontSize(fontSize: number) {
|
||||
if (fontSize < appconst.MinFontSize) {
|
||||
fontSize = appconst.MinFontSize;
|
||||
@ -323,6 +347,7 @@ class Model {
|
||||
}
|
||||
mobx.action(() => {
|
||||
this.termFontSize.set(fontSize);
|
||||
this.bumpRenderVersion();
|
||||
})();
|
||||
}
|
||||
|
||||
@ -1114,6 +1139,15 @@ class Model {
|
||||
shortcut = clientData?.clientopts?.globalshortcut;
|
||||
}
|
||||
getApi().reregisterGlobalShortcut(shortcut);
|
||||
let fontFamily = clientData?.feopts?.termfontfamily;
|
||||
if (fontFamily == null) {
|
||||
fontFamily = "JetBrains Mono";
|
||||
}
|
||||
loadFonts(fontFamily);
|
||||
document.fonts.ready.then(() => {
|
||||
clearMonoFontCache();
|
||||
this.bumpRenderVersion();
|
||||
});
|
||||
}
|
||||
|
||||
submitCommandPacket(cmdPk: FeCmdPacketType, interactive: boolean): Promise<CommandRtnType> {
|
||||
@ -1452,4 +1486,4 @@ class Model {
|
||||
}
|
||||
}
|
||||
|
||||
export { Model };
|
||||
export { Model, getApi };
|
||||
|
@ -190,7 +190,8 @@ class RemotesModel {
|
||||
},
|
||||
focusHandler: this.setRemoteTermWrapFocus.bind(this),
|
||||
isRunning: true,
|
||||
fontSize: this.globalModel.termFontSize.get(),
|
||||
fontSize: this.globalModel.getTermFontSize(),
|
||||
fontFamily: this.globalModel.getTermFontFamily(),
|
||||
ptyDataSource: getTermPtyData,
|
||||
onUpdateContentHeight: null,
|
||||
});
|
||||
|
@ -588,7 +588,8 @@ class Screen {
|
||||
focusHandler: (focus: boolean) => this.setLineFocus(line.linenum, focus),
|
||||
isRunning: cmd.isRunning(),
|
||||
customKeyHandler: this.termCustomKeyHandler.bind(this),
|
||||
fontSize: this.globalModel.termFontSize.get(),
|
||||
fontSize: this.globalModel.getTermFontSize(),
|
||||
fontFamily: this.globalModel.getTermFontFamily(),
|
||||
ptyDataSource: getTermPtyData,
|
||||
onUpdateContentHeight: (termContext: RendererContext, height: number) => {
|
||||
this.globalModel.setContentHeight(termContext, height);
|
||||
|
@ -90,7 +90,8 @@ class SpecialLineContainer {
|
||||
focusHandler: null,
|
||||
isRunning: cmd.isRunning(),
|
||||
customKeyHandler: null,
|
||||
fontSize: this.globalModel.termFontSize.get(),
|
||||
fontSize: this.globalModel.getTermFontSize(),
|
||||
fontFamily: this.globalModel.getTermFontFamily(),
|
||||
ptyDataSource: getTermPtyData,
|
||||
onUpdateContentHeight: null,
|
||||
});
|
||||
|
@ -337,8 +337,8 @@ class SourceCodeRenderer extends React.Component<
|
||||
onMount={this.handleEditorDidMount}
|
||||
options={{
|
||||
scrollBeyondLastLine: false,
|
||||
fontSize: GlobalModel.termFontSize.get() * 0.9,
|
||||
/* fontFamily: "Martian Mono", */
|
||||
fontSize: GlobalModel.getTermFontSize(),
|
||||
fontFamily: GlobalModel.getTermFontFamily(),
|
||||
readOnly: !this.getAllowEditing(),
|
||||
}}
|
||||
onChange={this.handleEditorChange}
|
||||
|
@ -31,6 +31,7 @@ type TermWrapOpts = {
|
||||
isRunning: boolean;
|
||||
customKeyHandler?: (event: any, termWrap: TermWrap) => boolean;
|
||||
fontSize: number;
|
||||
fontFamily: string;
|
||||
ptyDataSource: (termContext: TermContextUnion) => Promise<PtyDataType>;
|
||||
onUpdateContentHeight: (termContext: RendererContext, height: number) => void;
|
||||
};
|
||||
@ -53,6 +54,7 @@ class TermWrap {
|
||||
focusHandler: (focus: boolean) => void;
|
||||
isRunning: boolean;
|
||||
fontSize: number;
|
||||
fontFamily: string;
|
||||
onUpdateContentHeight: (termContext: RendererContext, height: number) => void;
|
||||
ptyDataSource: (termContext: TermContextUnion) => Promise<PtyDataType>;
|
||||
initializing: boolean;
|
||||
@ -67,6 +69,7 @@ class TermWrap {
|
||||
this.focusHandler = opts.focusHandler;
|
||||
this.isRunning = opts.isRunning;
|
||||
this.fontSize = opts.fontSize;
|
||||
this.fontFamily = opts.fontFamily;
|
||||
this.ptyDataSource = opts.ptyDataSource;
|
||||
this.onUpdateContentHeight = opts.onUpdateContentHeight;
|
||||
this.initializing = true;
|
||||
@ -88,7 +91,7 @@ class TermWrap {
|
||||
rows: this.termSize.rows,
|
||||
cols: this.termSize.cols,
|
||||
fontSize: opts.fontSize,
|
||||
fontFamily: "JetBrains Mono",
|
||||
fontFamily: opts.fontFamily,
|
||||
theme: { foreground: terminal.foreground, background: terminal.background },
|
||||
});
|
||||
this.terminal.loadAddon(
|
||||
|
10
src/types/custom.d.ts
vendored
10
src/types/custom.d.ts
vendored
@ -471,6 +471,7 @@ declare global {
|
||||
idealSize: WindowSize;
|
||||
termOpts: TermOptsType;
|
||||
termFontSize: number;
|
||||
termFontFamily: string;
|
||||
};
|
||||
|
||||
type RendererOptsUpdate = {
|
||||
@ -558,6 +559,7 @@ declare global {
|
||||
|
||||
type FeOptsType = {
|
||||
termfontsize: number;
|
||||
termfontfamily: string;
|
||||
};
|
||||
|
||||
type ConfirmFlagsType = {
|
||||
@ -589,6 +591,13 @@ declare global {
|
||||
fullscreen: boolean;
|
||||
};
|
||||
|
||||
type KeyModsType = {
|
||||
meta?: boolean;
|
||||
ctrl?: boolean;
|
||||
alt?: boolean;
|
||||
shift?: boolean;
|
||||
};
|
||||
|
||||
type ClientDataType = {
|
||||
clientid: string;
|
||||
userid: string;
|
||||
@ -847,6 +856,7 @@ declare global {
|
||||
getPlatform: () => string;
|
||||
getAuthKey: () => string;
|
||||
getWaveSrvStatus: () => boolean;
|
||||
getInitialTermFontFamily: () => string;
|
||||
restartWaveSrv: () => boolean;
|
||||
reloadWindow: () => void;
|
||||
openExternalLink: (url: string) => void;
|
||||
|
@ -242,9 +242,19 @@ function incObs(inum: mobx.IObservableValue<number>) {
|
||||
})();
|
||||
}
|
||||
|
||||
// @check:font
|
||||
function loadFonts() {
|
||||
const jbmFontNormal = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-regular.woff2')", {
|
||||
function addToFontFaceSet(fontFaceSet: FontFaceSet, fontFace: FontFace) {
|
||||
// any cast to work around typing issue
|
||||
(fontFaceSet as any).add(fontFace);
|
||||
}
|
||||
|
||||
let isJetBrainsMonoLoaded = false;
|
||||
|
||||
function loadJetBrainsMonoFont() {
|
||||
if (isJetBrainsMonoLoaded) {
|
||||
return;
|
||||
}
|
||||
isJetBrainsMonoLoaded = true;
|
||||
let jbmFontNormal = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-regular.woff2')", {
|
||||
style: "normal",
|
||||
weight: "400",
|
||||
});
|
||||
@ -256,19 +266,78 @@ function loadFonts() {
|
||||
style: "normal",
|
||||
weight: "700",
|
||||
});
|
||||
const faFont = new FontFace("FontAwesome", "url(public/fonts/fontawesome-webfont-4.7.woff2)", {
|
||||
style: "normal",
|
||||
weight: "normal",
|
||||
});
|
||||
const docFonts: any = document.fonts; // work around ts typing issue
|
||||
docFonts.add(jbmFontNormal);
|
||||
docFonts.add(jbmFont200);
|
||||
docFonts.add(jbmFont700);
|
||||
docFonts.add(faFont);
|
||||
addToFontFaceSet(document.fonts, jbmFontNormal);
|
||||
addToFontFaceSet(document.fonts, jbmFont200);
|
||||
addToFontFaceSet(document.fonts, jbmFont700);
|
||||
jbmFontNormal.load();
|
||||
jbmFont200.load();
|
||||
jbmFont700.load();
|
||||
}
|
||||
|
||||
let isHackFontLoaded = false;
|
||||
|
||||
function loadHackFont() {
|
||||
if (isHackFontLoaded) {
|
||||
return;
|
||||
}
|
||||
isHackFontLoaded = true;
|
||||
let hackRegular = new FontFace("Hack", "url('public/fonts/hack-regular.woff2')", {
|
||||
style: "normal",
|
||||
weight: "400",
|
||||
});
|
||||
let hackBold = new FontFace("Hack", "url('public/fonts/hack-bold.woff2')", {
|
||||
style: "normal",
|
||||
weight: "700",
|
||||
});
|
||||
let hackItalic = new FontFace("Hack", "url('public/fonts/hack-italic.woff2')", {
|
||||
style: "italic",
|
||||
weight: "400",
|
||||
});
|
||||
let hackBoldItalic = new FontFace("Hack", "url('public/fonts/hack-bolditalic.woff2')", {
|
||||
style: "italic",
|
||||
weight: "700",
|
||||
});
|
||||
addToFontFaceSet(document.fonts, hackRegular);
|
||||
addToFontFaceSet(document.fonts, hackBold);
|
||||
addToFontFaceSet(document.fonts, hackItalic);
|
||||
addToFontFaceSet(document.fonts, hackBoldItalic);
|
||||
hackRegular.load();
|
||||
hackBold.load();
|
||||
hackItalic.load();
|
||||
hackBoldItalic.load();
|
||||
}
|
||||
|
||||
let isBaseFontsLoaded = false;
|
||||
|
||||
function loadBaseFonts() {
|
||||
if (isBaseFontsLoaded) {
|
||||
return;
|
||||
}
|
||||
isBaseFontsLoaded = true;
|
||||
let faFont = new FontFace("FontAwesome", "url(public/fonts/fontawesome-webfont-4.7.woff2)", {
|
||||
style: "normal",
|
||||
weight: "normal",
|
||||
});
|
||||
let mmFont = new FontFace("Martian Mono", "url(public/fonts/MartianMono-VariableFont_wdth,wght.ttf)", {
|
||||
style: "normal",
|
||||
weight: "normal",
|
||||
});
|
||||
addToFontFaceSet(document.fonts, faFont);
|
||||
addToFontFaceSet(document.fonts, mmFont);
|
||||
faFont.load();
|
||||
mmFont.load();
|
||||
}
|
||||
|
||||
function loadFonts(termFont: string) {
|
||||
loadBaseFonts();
|
||||
loadJetBrainsMonoFont();
|
||||
if (termFont == "Hack") {
|
||||
loadHackFont();
|
||||
}
|
||||
document.documentElement.style.setProperty(
|
||||
"--termfontfamily",
|
||||
'"' + termFont + '"' + ', "JetBrains Mono", monospace'
|
||||
);
|
||||
}
|
||||
|
||||
const DOW_STRS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
|
@ -5134,6 +5134,24 @@ func validateOpenAIModel(model string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
const MaxFontFamilyLen = 50
|
||||
|
||||
var fontfamilyRe = regexp.MustCompile(`^[a-zA-Z0-9_ -]+$`)
|
||||
|
||||
func validateFontFamily(fontFamily string) error {
|
||||
if len(fontFamily) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(fontFamily) > MaxFontFamilyLen {
|
||||
return fmt.Errorf("invalid font family, too long")
|
||||
}
|
||||
m := fontfamilyRe.MatchString(fontFamily)
|
||||
if !m {
|
||||
return fmt.Errorf("invalid font family, must match %q", fontfamilyRe.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ClientSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scbus.UpdatePacket, error) {
|
||||
clientData, err := sstore.EnsureClientData(ctx)
|
||||
if err != nil {
|
||||
@ -5156,6 +5174,20 @@ func ClientSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sc
|
||||
}
|
||||
varsUpdated = append(varsUpdated, "termfontsize")
|
||||
}
|
||||
if fontFamilyStr, found := pk.Kwargs["termfontfamily"]; found {
|
||||
newFontFamily := fontFamilyStr
|
||||
err = validateFontFamily(newFontFamily)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
feOpts := clientData.FeOpts
|
||||
feOpts.TermFontFamily = newFontFamily
|
||||
err = sstore.UpdateClientFeOpts(ctx, feOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error updating client feopts: %v", err)
|
||||
}
|
||||
varsUpdated = append(varsUpdated, "termfontfamily")
|
||||
}
|
||||
if apiToken, found := pk.Kwargs["openaiapitoken"]; found {
|
||||
err = validateOpenAIAPIToken(apiToken)
|
||||
if err != nil {
|
||||
@ -5244,7 +5276,7 @@ func ClientSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sc
|
||||
}
|
||||
}
|
||||
if len(varsUpdated) == 0 {
|
||||
return nil, fmt.Errorf("/client:set requires a value to set: %s", formatStrs([]string{"termfontsize", "openaiapitoken", "openaimodel", "openaibaseurl", "openaimaxtokens", "openaimaxchoices"}, "or", false))
|
||||
return nil, fmt.Errorf("/client:set requires a value to set: %s", formatStrs([]string{"termfontsize", "termfontfamily", "openaiapitoken", "openaimodel", "openaibaseurl", "openaimaxtokens", "openaimaxchoices"}, "or", false))
|
||||
}
|
||||
clientData, err = sstore.EnsureClientData(ctx)
|
||||
if err != nil {
|
||||
|
@ -296,6 +296,7 @@ type ClientOptsType struct {
|
||||
|
||||
type FeOptsType struct {
|
||||
TermFontSize int `json:"termfontsize,omitempty"`
|
||||
TermFontFamily string `json:"termfontfamily,omitempty"`
|
||||
}
|
||||
|
||||
type ReleaseInfoType struct {
|
||||
|
Loading…
Reference in New Issue
Block a user