
Uma biblioteca para imitar interfaces gráficas do sistema operacional na web
Especificamente, o Windows 98 - por enquanto, pelo menos; Pode ser expandido no futuro.
Esta biblioteca fornece 98.js.org, uma versão baseada na Web do Windows 98, incluindo tinta, bloco de notas, gravador de som e muito mais.
Veja a página inicial para obter mais informações.
Barras de menu, com suporte para caixa de seleção e itens de rádio, estados deficientes, submenus, atalhos de teclado e muito mais
Janelas de aplicativos que você pode arrastar, maximizar, minimizar, fechar e redimensionar
Variantes de diálogo e janela de ferramentas
Animação voadora da barra de título que guia seus olhos durante maximizar/minimizar/restaurar
Contenção de foco: se você guiar ou mudar+guia dentro de uma janela, ela envolve o primeiro/último controle.
Estilos de botão, incluindo botões leves, botões desativados e botões de ação padrão
Estilos de barra de rolagem, específicos para o webkit (no futuro, pode haver uma barra de rolagem personalizada com base em uma biblioteca não invasiva de barra de rolagem, ou estilos que suportam uma biblioteca, onde se espera que use a biblioteca diretamente)
Timeable com o Windows .theme & .themepack FILOS NA RUNDO !
Veja demos online aqui
Atualmente, esta biblioteca requer jQuery para a implementação de janelas. As barras de menu não requerem jQuery.
(Eventualmente, quero ter dependências. Até agora, removi o jQuery do código do menu ...)
A biblioteca ainda não foi fornecida como um único arquivo conveniente.
Você pode 1. Faça o download do repositório como um arquivo zip, 2. Clone o repositório ou 3. Instale a biblioteca como um pacote NPM.
Você deve incluir scripts para os componentes que deseja usar ( MenuBar.js ou $Window.js ), juntamente com folhas de estilo para layout, um tema e um esquema de cores.
Certifique -se de usar os arquivos CSS compilados, não os arquivos de origem.
Em <head> :
< link href =" os-gui/layout.css " rel =" stylesheet " type =" text/css " >
< link href =" os-gui/windows-98.css " rel =" stylesheet " type =" text/css " >
< link href =" os-gui/windows-default.css " rel =" stylesheet " type =" text/css " > Em <head> ou <body> :
< script src =" os-gui/MenuBar.js " > </ script >
< script src =" lib/jquery.js " > </ script > <!-- required by $Window.js -->
< script src =" os-gui/$Window.js " > </ script > Nota : A API provavelmente mudará muito, mas eu mantenho um Changelog.
.inset-deep cria uma borda de 2px.outset-deep cria uma borda inserida de 2px (como um botão ou janela ou pop-up de menu).inset-shallow cria uma borda de 1px.outset-shallow cria uma borda de 1px Os estilos de botão são aplicados aos elementos button globalmente. (E se você quiser redefini -lo, observe que precisa se livrar do elemento pseudo ::after . @Todo: SCOPE CSS)
Para fazer um botão de alternância, adicione a classe .toggle ao botão. Faça -o mostrar como pressionado com a classe .selected . (@Todo: renomeie isso .pressed
Você deve usar os estilos juntamente com atributos semânticos aria-pressed , aria-haspopup e/ou aria-expanded conforme apropriado.
Você pode mostrar o botão é a ação padrão adicionando .default ao botão. Observe que no Windows 98, esse estilo passa de botão para botão, dependendo do foco. Uma regra geral é que ela deve estar no botão que acionará o Enter.
Você pode criar um botão leve adicionando .lightweight ao botão. Os botões leves são sutis e não têm fronteira até o mouse.
Você pode desativar um botão adicionando o atributo padrão disabled ao botão.
Você pode mostrar um botão como sendo pressionado adicionando a classe .pressing ao botão.
Isso é útil para botões que são acionados por um pressionamento de teclas.
Os estilos de barra de rolagem são aplicados globalmente, mas eles têm um prefixo -webkit- , para que eles só funcionem em navegadores "baseados em webkit", geralmente, como Chrome, Safari e Opera.
(Pode ser substituído com ::-webkit-scrollbar e seletores relacionados (mas não é facilmente redefinido para o padrão do navegador, a menos que -webkit-appearance: scrollbar Works ... @Todo: Scope CSS)
Os estilos de seleção são aplicados globalmente.
(Pode ser substituído com ::selection (mas não é facilmente redefinido para o padrão do navegador ... a menos que unset
MenuBar(menus)Cria um componente da barra de menus.
menus devem ser um objeto segurando matrizes de especificações do item de menu, com o nome do botão de menu.
Retorna um objeto com element da propriedade, que você deve anexar ao DOM onde deseja.
Veja exemplos no código de demonstração.
elementO elemento DOM que representa a barra de menus.
closeMenus()Fecha todos os menus que estão abertos.
setKeyboardScope(...eventTargets)As teclas de atalho como o ALT serão tratadas no nível do (s) elemento (s) ou alvo (s) de eventos.
Por padrão, o escopo é window (global), para o caso de um aplicativo de uma página em que a barra de menus está na parte superior. Se você estiver colocando a barra de menus em uma janela, deve ligar para o elemento da janela:
menu_bar . setKeyboardScope ( $window . element ) ;ou melhor ainda,
$window . setMenuBar ( menu_bar ) ;que cuida do escopo do teclado para você, enquanto anexa a barra de menus na janela.
Observe que algum comportamento do teclado é sempre tratado se a barra de menus tiver foco.
Observe também para iframes, pode ser necessário ligar para isso com $window[0], iframe.contentWindow atualmente, mas isso deve ser alterado no futuro (os eventos do teclado devem ser proxiados).
info Pode ser usado para implementar uma barra de status. Uma descrição é fornecida como event.detail.description ao rolar itens de menu que especificam uma description . Por exemplo:
menubar . element . addEventListener ( "info" , ( event ) => {
statusBar . textContent = event . detail ?. description || "" ;
} ) ; default-infoSinaliza que uma barra de status deve ser redefinida para em branco ou uma mensagem padrão.
menubar . element . addEventListener ( "default-info" , ( event ) => {
statusBar . textContent = "" ;
// or:
statusBar . textContent = "For Help, click Help Topics on the Help Menu." ;
// like in MS Paint (and JS Paint)
// or:
statusBar . textContent = "For Help, press F1." ;
// like WordPad
// or perhaps even:
statusBar . innerHTML = "For Help, <a href='docs'>click here</a>" ;
// Note that a link is not a common pattern, and it could only work for the default text;
// for menu item descriptions the message in the status bar is transient, so
// you wouldn't be able to reach it to click on it.
} ) ; As especificações do item de menu são MENU_DIVIDER (uma constante indicando uma regra horizontal) ou uma especificação do grupo de rádio ou um objeto com as seguintes propriedades:
label : um rótulo para o item; AMPERSANDS Definir teclas de acesso (para usar um ampersa literal e, use && )shortcutLabel (Opcional): Um atalho de teclado para mostrar o item, como "Ctrl+A" (Nota: você precisa ouvir o atalho, diferentemente das teclas de acesso)ariaKeyShortcuts (Opcional): aria-keyshortcuts para o item, como "Control+A meta+A", para leitores de tela. "Ctrl" não é válido (você deve soletrar) e é melhor fornecer uma alternativa para o macOS, geralmente com a chave de comando equivalente, usando "meta" (e event.metaKey ).action (Opcional): uma função a ser executada quando o item é clicado (pode especificar apenas action ou checkbox )checkbox (opcional): um objeto especificando que este item deve se comportar como uma caixa de seleção.check da propriedade deste objeto deve ser uma função que verifique se o item deve ser verificado ou não, retornando true para verificado e false para não verificado. Que nome fofo.toggle da propriedade deve ser uma função que alterna o estado da opção, no entanto, você está armazenando; chamado quando clicado.enabled (opcional): pode ser false para desativar incondicionalmente o item ou uma função que determina se o item deve ser ativado, retornando true para ativar o item, false para desativar.submenu (opcional): uma variedade de especificações do item de menu para criar um submenudescription (Opcional): para implementar uma barra de status; Um evento info é emitido ao rolar sobre o item com esta descriçãovalue (Opcional): Para itens de rádio, o valor do item; pode ser qualquer tipo, mas === é usado para determinar se o item está verificado.Uma especificação do grupo de rádio é um objeto com as seguintes propriedades:
radioItems : uma matriz de especificações do item de menu para criar um grupo de botões de rádio. Ao contrário submenu , os itens estão incluídos diretamente neste menu. Recomenda -se separar o grupo de rádio de outros itens de menu com um MENU_DIVIDER .getValue : uma função que deve retornar o valor do item de rádio selecionado.setValue : uma função que deve alterar o estado para o valor fornecido, de maneira específica do aplicativo.ariaLabel (OPCIONAL): Uma string a ser usada como aria-label para o grupo de rádio (para a acessibilidade do leitor de tela)Os menus podem ser navegados com teclas de atalho contextuais conhecidas como chaves de acesso .
Coloque um ampers e antes de uma carta em um botão de menu ou rótulo do item de menu para torná -lo uma chave de acesso. A Microsoft possui documentação sobre chaves de acesso, incluindo diretrizes para escolher as chaves de acesso. Geralmente, a primeira letra é uma boa escolha.
Se um item de menu não definir uma chave de acesso, a primeira letra do rótulo poderá ser usada para acessá -la.
Para os botões do menu, você precisa segurar o ALT ao pressionar a tecla de acesso do botão, mas para os itens de menu nos pop -ups de menu, você deve pressionar a tecla diretamente, pois o ALT fechará os menus.
Se houver vários itens de menu com a mesma tecla de acesso, ele percorrerá entre eles sem ativá -los. Você deve tentar tornar as teclas de acesso exclusivas, incluindo as teclas de acesso definidas e as primeiras letras dos itens de menu sem chaves de acesso definidas. (Esse comportamento é observado no Windows 98, no menu Favoritos do Explorer, onde você pode fazer marcadores com a primeira letra que corresponde às teclas de acesso de outros itens de menu.)
Existe um objeto AccessKeys exportado pelo MenuBar.js , com funções para lidar com as chaves de acesso:
AccessKeys.escape(label)Escapa de amperas e no rótulo fornecido, para que não sejam interpretados como teclas de acesso.
Isso é útil para menus dinâmicos, como um menu de história que usa títulos de página como rótulos. Você não deseja que os eragens sejam intimamente interpretados como chaves de acesso, ou amperas duplos para serem interpretados como um único ampérs e.
AccessKeys.unescape(label)On-Escape todos os dois e duplos de e-mails no rótulo.
Para renderizar, use toHTML ou toFragment .
AccessKeys.has(label)Retorna true se o rótulo tiver uma chave de acesso.
AccessKeys.get(label)Retorna a chave de acesso para o rótulo fornecido, ou nulo, se não.
MenuBar lida com as teclas de acesso automaticamente, mas se você estiver incluindo teclas de acesso para outros elementos da interface do usuário, precisará lidar com elas você mesmo, e poderá usá-lo em vez de codificar a tecla de acesso, para que ela não precise ser alterada em dois lugares.
AccessKeys.remove(label) Remove o indicador de chave de acesso ( & ) do rótulo e não-escapa qualquer amperagem dupla. Também remove um indicador de chave de acesso entre parênteses, como "(& n)", como um caso especial.
AccessKeys.toText(label) Remove o indicador de chave de acesso ( & ) do rótulo e não-escapa qualquer amperagem dupla. É como toHTML , mas para texto simples.
Nota : Embora as teclas de acesso geralmente façam parte de uma palavra, como "& new", nas traduções, elas geralmente são indicadas separadamente, como "새로 만들기 (& n)", uma vez que a tecla de acesso permanece a mesma, mas a letra não faz mais parte da palavra (ou mesmo o alfabeto). Esta função não remove strings como "(& n)", removerá apenas o "&" e deixará "새로 만들기 (n)". Se você quiser esse comportamento, use AccessKeys.remove(label) .
AccessKeys.toHTML(label) Retorna o HTML (com escape adequado) com a tecla de acesso como um elemento <span class='menu-hotkey'> .
Nota de segurança : é seguro usar o resultado dessa função no conteúdo do elemento HTML, pois escapa do rótulo. Não é seguro usar um valor de atributo, mas esse não é o uso pretendido.
Nota de layout : você pode querer cerca o resultado com <span style="white-space: pre"> para impedir que o espaço em branco desmoronize se a chave de acesso estiver próxima a um espaço.
AccessKeys.toFragment(label) Retorna um DocumentFragment com a chave de acesso como um elemento <span class='menu-hotkey'> .
Nota de layout : você pode querer cerca o resultado com <span style="white-space: pre"> para impedir que o espaço em branco desmoronize se a chave de acesso estiver próxima a um espaço.
$Window(options)Cria um componente de janela que pode ser arrastado e tal, trazido para a frente quando clicado e fechado. Diferentes tipos de janelas podem ser criados com diferentes opções. Observe que o foco envolve o conteúdo de uma janela.
Retorna um objeto jQuery com métodos e propriedades adicionais (veja abaixo, após opções).
O nó DOM pode ser acessado com $window.element , e o objeto $Window pode ser acessado no nó DOM com o element.$window .
|
Retorna um objeto jQuery com métodos e propriedades adicionais:
title(text) Define o título, ou se text não for passado, retorna o título atual da janela.
close(force=false)Fecha a janela.
Se force for true , o evento "fechado" não será emitido e a janela será fechada imediatamente.
focus()Tenta concentrar algo dentro da janela, nesta ordem de prioridade:
class="default"$window.$content ) blur()Remove o foco da janela. Se o foco estiver fora da janela, ele permanece inalterado.
minimize() Minimiza a janela. Se $window.task.$task estiver definida, ele o usará como um alvo para minimizar, caso contrário, a janela minimizará a parte inferior da tela.
O comportamento atual é que ele alterna a minimização. Isso pode mudar no futuro.
maximize() Maximiza a janela. Embora maximizado, a janela usará position: fixed , para que não role com a página.
O comportamento atual é que ele alterna a maximização. Isso pode mudar no futuro. Além disso, se minimizado, restaurará em vez de maximizar. Basicamente, faz o que o botão Maximize faz, em vez de simplesmente o que o nome do método sugere.
unminimize() Privado: não use isso. Use restore() em vez disso.
Restaura a janela do estado minimizado.
restore()Restaura a janela do estado minimizado ou maximizado. Se a janela não for minimizada ou maximizada, esse método não fará nada.
center()Centra a janela da página. Você deve chamar isso após o conteúdo da janela ser totalmente renderizado, ou você definiu um tamanho fixo para a janela.
Se você tiver imagens na janela, aguarde que elas carreguem antes de mostrar e centralizar a janela ou definir um tamanho fixo para as imagens.
applyBounds()Se encaixa na janela dentro da página, se estiver parcialmente fora da tela. (Não redimensione a janela se for muito grande; sairá da direita e da tela.)
bringTitleBarInBounds()Reposiciona a janela para que a barra de título fique dentro dos limites da página, para que possa ser arrastada.
bringToFront() Traz a janela para a frente, definindo seu z-index como maior que qualquer z-index ainda usado pelo sistema de janelas.
setDimensions({ innerWidth, innerHeight, outerWidth, outerHeight }) Define o tamanho da janela. Passe { innerWidth, innerHeight } para especificar o tamanho em termos do conteúdo da janela, ou { outerWidth, outerHeight } para especificar o tamanho, incluindo o quadro da janela.
(Isso pode ser expandido no futuro para permitir a definição da posição também ...)
setIcons(icons) Altera o ícone (s) da janela. icons estão no mesmo formato que options.icons .
setTitlebarIconSize(size)Define o tamanho do ícone da barra de título da janela, escolhendo o tamanho mais próximo disponível.
getTitlebarIconSize()Retorna o tamanho do ícone da barra de título da janela.
getIconAtSize(size) Escolha o tamanho mais próximo do ícone disponível e retorna um nó DOM exclusivo (ou seja, clonado) ou null se nenhum ícones for definido.
Isso pode ser usado para representar a janela na barra de tarefas.
setMenuBar(menuBar)Anexa a barra de menus na janela e define o escopo do teclado para as teclas de atalho da barra de menus para a janela.
Pode ser chamado com null para remover a barra de menus.
setMinimizeTarget(minimizeTargetElement) O destino minimize (botão da barra de tarefas) representa a janela quando minimizado e é usado para animar minimizar e restaurar. Se minimizeTargetElement for null , a janela minimizará a parte inferior da tela (o padrão).
$Button(text, action)Cria um botão na área de conteúdo da janela. Ele fecha automaticamente a janela quando clicado. Não existe uma maneira (boa) de impedir isso, pois se destina apenas a diálogos.
Se você precisar de outro comportamento, basta criar um <button> e adicioná -lo à área de conteúdo da janela.
Retorna um objeto jQuery.
addChildWindow($window)Privado: não use isso.
Define uma janela quando criança. Para janelas de ferramentas, o estado de foco será compartilhado com a janela dos pais.
Isso é usado internamente quando você define options.parentWindow ao criar uma janela.
onFocus(listener)Liga o ouvinte quando a janela está (visualmente?) Focada.
Retorna uma função para remover o ouvinte.
onBlur(listener)Liga o ouvinte quando a janela (visualmente?) Perde o foco.
Retorna uma função para remover o ouvinte.
onClosed(listener)Ligue para o ouvinte quando a janela é fechada (após o emitido do evento de fechamento e se não foi impedido).
Retorna uma função para remover o ouvinte.
onBeforeClose(listener) Liga o ouvinte antes que a janela seja fechada. Se o ouvinte ligar para event.preventDefault() , a janela não será fechada.
Retorna uma função para remover o ouvinte.
Este evento é útil para confirmar com o usuário antes de fechar uma janela, por exemplo.
$window.close(true) pode ser usado para ignorar este evento (e a confirmação) quando a janela deve ser realmente fechada.
Se você não vai evitar o fechamento da janela, provavelmente deve usar o evento closed , pois, hipoteticamente, outro ouvinte poderá impedir o fechamento após o ouvinte, levando à limpeza prematura.
onBeforeDrag(listener) Ligue para o ouvinte antes que a janela seja arrastada pela barra de título. Se o ouvinte ligar para event.preventDefault() , o arrasto será evitado.
Retorna uma função para remover o ouvinte.
Este evento permite substituir o comportamento de arrasto das janelas de cores e ferramentas na tinta js.
onTitleChange(listener)Ligue para o ouvinte quando o título da janela muda.
Retorna uma função para remover o ouvinte.
Este evento pode ser usado para atualizar o rótulo de um botão da barra de tarefas.
onIconChange(listener)Ligue para o ouvinte quando o ícone da janela muda.
Retorna uma função para remover o ouvinte.
Este evento pode ser usado para atualizar o ícone de um botão da barra de tarefas. Use $window.getIconAtSize(size) para obter um ícone apropriado.
closedSe a janela foi fechada.
icons Os ícones da janela em tamanhos diferentes, conforme definido por options.icons ou setIcons() .
elementsUm objeto que contém referências aos elementos da janela.
content (htmlelement)A área de conteúdo da janela.
titlebar (htmlelement)A barra de título da janela, incluindo o título, os botões da janela e possivelmente um ícone.
_title_area (htmlelement)Um elemento de invólucro em torno do título.
Privado: não use isso. Use elements.titlebar ou elements.title , se possível.
title (htmlelement)O título da janela.
closeButton (htmlbuttonElement)O botão de fechar a janela.
minimizeButton (htmlbuttonElement)O botão de minimizar a janela.
maximizeButton (htmlbuttonElement)O botão de maximizar da janela.
$content objeto jQuery.
Onde você pode anexar o conteúdo à janela.
$titlebar objeto jQuery.
A barra de título da janela, incluindo o título, os botões da janela e possivelmente um ícone.
$title_area Privado: não use isso. Use $title ou $titlebar , se possível.
objeto jQuery.
Invólucro em torno do título.
$title objeto jQuery.
A parte do título da barra de título.
$x objeto jQuery.
O botão Fechar.
$minimize objeto jQuery.
O botão Minimize.
$maximize objeto jQuery.
O botão de maximizar.
$iconPrivado: não use isso.
objeto jQuery.
O ícone do título da BARBA.
elementO elemento DOM que representa a janela.
close Depreciado: use o método onBeforeClose .
Pode ser usado para evitar o fechamento de uma janela, com event.preventDefault() . Como pode haver vários ouvintes e outro ouvinte pode evitar o fechamento, se você quiser detectar quando a janela estiver realmente fechada, use o evento closed .
closed Depreciado: use o método onClosed .
Este evento é emitido quando a janela é fechada. Não pode ser evitado.
window-drag-start Despregado: use o método onBeforeDrag .
Pode ser usado para evitar arrastar uma janela, com event.preventDefault() .
title-change Despregado: use o método onTitleChange .
Pode ser usado para atualizar o rótulo de um botão da barra de tarefas.
icon-change Despregado: use o método onIconChange .
Pode ser usado para atualizar o ícone de um botão de barra de tarefa. Use $window.getIconAtSize(size) para obter um ícone apropriado.
Além do center() , não há API especificamente para posicionar o Windows.
Você pode usar $($window.element).css({ top: "500px", left: "500px" }) para definir a posição da janela com o método css() de jQuery, ou usar:
$window . element . style . top = "500px" ;
$window . element . style . left = "500px" ; Você também pode definir position para fixed ou absolute para posicionar a janela em relação à viewport ou ao ancestral posicionado mais próximo, respectivamente.
Se você deseja posicionar uma janela em relação a outra janela, poderá usar $otherWindow.element.getBoundingClientRect() para obter o retângulo delimitador da outra janela e use -a para posicionar a janela. Esta é uma API DOM embutida. Por exemplo:
const otherRect = $otherWindow . element . getBoundingClientRect ( ) ;
$window . element . top = ` ${ otherRect . top } px` ;
$window . element . left = ` ${ otherRect . right + 10 } px` ; !important ) para posicionar a janela, porque a biblioteca usa estilos embutidos para posicionar a janela, que têm precedência.setDimensions() no futuro para permitir o posicionamento da janela, além de dimensioná -lo ou adicionar um método setPosition() .options.constrainRect para restringir dinamicamente a posição e o tamanho da janela durante o arrasto e o redimensionamento. parse-theme.js contém funções para analisar e aplicar temas.
parseThemeFileString(themeString)Analisa uma sequência de arquivos ini nas propriedades CSS.
Renderiza automaticamente gráficos de tema dinâmico e os inclui nas propriedades CSS.
applyCSSProperties(cssProperties, {element=document.documentElement, recurseIntoIframes=false}) cssProperties é um objeto com propriedades e valores CSS. Também pode ser um objeto CSSStyleDeclaration .
element é o elemento para aplicar as propriedades a.
Se recurseIntoIframes for verdadeiro, as propriedades serão aplicadas a todos os elementos <iframe> também dentro do elemento. Isso funciona apenas com iframes da mesma origem.
renderThemeGraphics(cssProperties)Pode ser usado para atualizar gráficos temáticos (ícones da barra de rolagem, etc.) para uma seção específica da página. Usado pela demonstração para mostrar variações.
Retorna as propriedades do CSS que representam os gráficos temas renderizados.
element . style . setProperty ( '--scrollbar-size' , '30px' ) ;
applyCSSProperties ( renderThemeGraphics ( getComputedStyle ( element ) ) , { element } ) ; makeThemeCSSFile(cssProperties)Exporta um arquivo CSS para um tema. Presume que os gráficos temáticos já sejam renderizados. Inclui um comentário de "arquivo gerado".
makeBlackToInsetFilter()Inicializa um filtro SVG que pode ser usado para fazer com que os ícones pareçam desativados. Pode não funcionar com todos os ícones, pois usa as partes pretas da imagem para formar uma forma.
Uso do CSS:
button : disabled . icon {
filter : saturate ( 0 % ) opacity ( 50 % ); /* fallback until SVG filter is initialized */
filter : url ( "#os-gui-black-to-inset-filter" );
}Licenciado sob a licença do MIT, consulte a licença para obter detalhes.
Instale o Node.js se você ainda não o possui.
Clone o repositório e, no diretório do projeto, execute npm i para instalar as dependências. Execute também npm i ao fazer alterações no repositório, caso haja alterações nas dependências.
Execute npm start a abrir um servidor de desenvolvimento. Ele abrirá uma página de demonstração no seu navegador padrão. As alterações na biblioteca serão recompiladas automaticamente e a página será recarregada automaticamente.
Execute npm run lint para executar a verificação do tipo e a verificação de ortografia (e quaisquer outras tarefas de linha).
Execute npm test para executar os testes. Isso também salva relatórios de cobertura no diretório coverage , mas observe que ele registra apenas o código coberto por testes de unidade, ou seja, o código importado diretamente para os testes, não o código carregado no contexto da página, pois isso requer uma configuração adicional para instrumentação.
É uma boa ideia fechar o servidor ao atualizar ou instalar dependências; Caso contrário, você poderá encontrar problemas de EPERM.
Os estilos são escritos com postcss, para mixins e outras transformações.
Recomendado: Instale um plug -in de idioma PostCSS para o seu editor, como suporte de idioma PostCSS para o código VS.
Atualmente, existem alguns CSs que precisam ser regenerados manualmente no navegador e copiados em arquivos CSS específicos do tema.
No futuro, isso pode ser feito com um analisador de sintaxe PostCSS personalizado para arquivos .TheMe/.TheMepack, e talvez SVG em vez de qualquer gráfico raster para evitar a necessidade de node-canvas (as dependências nativas são uma dor). Ou talvez upng.js e manipulação de pixels simples.