[TGUI v6] Migration to CSS Variables, styles refactor & React 19 (#17487)

* Initial Port of tg's tgui 2.0

* initial

* first UI fixes

* fix retro theme

* rd console

* wiki theme

* better tgui say handling

* Ui scaling port

* smaller gap

* guh

* reset subcats on main cat change

* blink a bit later

* tofixed

* fixed

* currently not fully supported

* increase that

* fix powermonitor chart

* typescript up

* tgui core up
This commit is contained in:
Kashargul
2025-04-08 22:49:38 +02:00
committed by GitHub
parent e90a7a554a
commit d18cd11713
138 changed files with 2624 additions and 1987 deletions
+14 -2
View File
@@ -71,6 +71,14 @@
for (file in stylesheets)
head_content += "<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url(file)]'>"
if(user.client?.window_scaling && user.client?.window_scaling != 1 && !user.client?.prefs.read_preference(/datum/preference/toggle/ui_scale) && width && height)
head_content += {"
<style>
body {
zoom: [100 / user.client?.window_scaling]%;
}
</style>
"}
for (file in scripts)
head_content += "<script type='text/javascript' src='[SSassets.transport.get_asset_url(file)]'></script>"
@@ -108,8 +116,12 @@
to_chat(user, span_userdanger("The [title] browser you tried to open failed a sanity check! Please report this on GitHub!"))
return
var/window_size = ""
if (width && height)
window_size = "size=[width]x[height];"
if(width && height)
if(user.client?.prefs?.read_preference(/datum/preference/toggle/ui_scale))
var/scaling = user.client.window_scaling
window_size = "size=[width * scaling]x[height * scaling];"
else
window_size = "size=[width]x[height];"
var/datum/asset/simple/namespaced/common/common_asset = get_asset_datum(/datum/asset/simple/namespaced/common)
common_asset.send(user)
if (stylesheets.len)
@@ -30,10 +30,6 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept
//Linked bluespace radios
var/list/linked_radios_weakrefs = list()
/obj/machinery/telecomms/processor/Initialize(mapload)
. = ..()
default_apply_parts()
/obj/machinery/telecomms/broadcaster/proc/link_radio(var/obj/item/radio/R)
if(!istype(R))
return
+6 -1
View File
@@ -2,12 +2,14 @@
/datum/admins/proc/player_panel_new()//The new one
if (!usr.client.holder)
return
var/ui_scale = owner.prefs.read_preference(/datum/preference/toggle/ui_scale)
var/dat = "<html><head><title>Admin Player Panel</title></head>"
//javascript, the part that does most of the work~
dat += {"
<head>
[!ui_scale && owner.window_scaling ? "<style>body {zoom: [100 / owner.window_scaling]%;}</style>" : ""]
<script type='text/javascript'>
var locked_tabs = new Array();
@@ -315,7 +317,10 @@
</body></html>
"}
usr << browse(dat, "window=players;size=600x480")
var/window_size = "size=600x480"
if(owner.window_scaling && ui_scale)
window_size = "size=[600 * owner.window_scaling]x[400 * owner.window_scaling]"
usr << browse(dat, "window=players;[window_size]")
//The old one
/datum/admins/proc/player_panel_old()
@@ -83,6 +83,8 @@
names = D.get_variables()
//sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects. //VOREStation edit - commented out, replaced with spawn(0) above
var/ui_scale = prefs?.read_preference(/datum/preference/toggle/ui_scale)
var/list/variable_html = list()
if (islist)
var/list/L = D
@@ -113,6 +115,7 @@
font-size: 8pt;
}
</style>
[!ui_scale && window_scaling ? "<style>body {zoom: [100 / window_scaling]%;}</style>" : ""]
</head>
<body onload='selectTextField()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
<script type="text/javascript">
@@ -277,7 +280,11 @@
</body>
</html>
"}
src << browse(html, "window=variables[refid];size=475x650") //VOREStation edit end
var/size_string = "size=475x650";
if(ui_scale && window_scaling)
size_string = "size=[475 * window_scaling]x[650 * window_scaling]"
src << browse(html, "window=variables[refid];[size_string]")
/client/proc/vv_update_display(datum/D, span, content)
src << output("[span]:[content]", "variables\ref[D].browser:replace_span")
+3
View File
@@ -180,3 +180,6 @@
/// Token used for the external chatlog api. Only valid for the current round.
var/chatlog_token
/// The DPI scale of the client. 1 is equivalent to 100% window scaling, 2 will be 200% window scaling
var/window_scaling
+8 -1
View File
@@ -296,9 +296,12 @@
)
addtimer(CALLBACK(src, PROC_REF(check_panel_loaded)), 30 SECONDS)
INVOKE_ASYNC(src, PROC_REF(acquire_dpi))
tgui_panel.initialize()
// Initialize tgui panel
tgui_say.initialize()
tgui_panel.initialize()
connection_time = world.time
connection_realtime = world.realtime
@@ -813,6 +816,10 @@
SEND_SIGNAL(src, COMSIG_CLIENT_CLICK, object, location, control, params, usr)
. = ..()
/// This grabs the DPI of the user per their skin
/client/proc/acquire_dpi()
window_scaling = text2num(winget(src, null, "dpi"))
#undef ADMINSWARNED_AT
#undef CURRENT_MINUTE
#undef CURRENT_SECOND
@@ -114,3 +114,16 @@
/datum/preference/text/preset_colors/apply_to_client(client/client, value)
return
/datum/preference/toggle/ui_scale
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "ui_scale"
savefile_identifier = PREFERENCE_PLAYER
default_value = FALSE // Set to true once lobby screen is migrated to tgui and browse are replaced with datum browser
/datum/preference/toggle/ui_scale/apply_to_client(client/client, value)
if(!istype(client))
return
INVOKE_ASYNC(client, TYPE_VERB_REF(/client, refresh_tgui))
client.tgui_say?.load()
@@ -75,6 +75,7 @@
laws.show_laws(src)
law_retries --
else
law_retries = 0
break
return
+1
View File
@@ -270,6 +270,7 @@
"size" = window_size,
"fancy" = user.read_preference(/datum/preference/toggle/tgui_fancy),
"locked" = user.read_preference(/datum/preference/toggle/tgui_lock),
"scale" = user.client.prefs.read_preference(/datum/preference/toggle/ui_scale),
),
"client" = list(
"ckey" = user.client.ckey,
+6 -5
View File
@@ -68,13 +68,14 @@
var/minimum_width = client?.prefs?.read_preference(/datum/preference/numeric/tgui_say_width) || 1
var/minimum_height = (client?.prefs?.read_preference(/datum/preference/numeric/tgui_say_height) || 1) * 20 + 10
winset(client, "tgui_say", "pos=410,400;size=360,30;is-visible=0;")
winset(client, "tgui_say", "pos=410,400;is-visible=0;")
window.send_message("props", list(
lightMode = client?.prefs?.read_preference(/datum/preference/toggle/tgui_say_light),
minimumWidth = minimum_width,
minimumHeight = minimum_height,
maxLength = max_length,
"lightMode" = client?.prefs?.read_preference(/datum/preference/toggle/tgui_say_light),
"scale" = client.prefs?.read_preference(/datum/preference/toggle/ui_scale),
"minimumWidth" = minimum_width,
"minimumHeight" = minimum_height,
"maxLength" = max_length,
))
stop_thinking()
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "typescript",
"version": "5.8.2-sdk",
"version": "5.8.3-sdk",
"main": "./lib/typescript.js",
"type": "commonjs",
"bin": {
+7 -7
View File
@@ -1,7 +1,7 @@
{
"private": true,
"name": "tgui-workspace",
"version": "5.0.3",
"version": "6.0.0",
"packageManager": "yarn@4.8.1",
"workspaces": [
"packages/*"
@@ -26,8 +26,8 @@
"@swc/jest": "^0.2.37",
"@types/jest": "^29.5.14",
"@types/node": "^22.9.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.1",
"@types/webpack-env": "^1.18.5",
"@types/wicg-file-system-access": "^2023.10.5",
"@typescript-eslint/eslint-plugin": "^8.28.0",
@@ -48,14 +48,14 @@
"jsdom": "^25.0.1",
"mini-css-extract-plugin": "^2.9.2",
"prettier": "^3.2.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"sass": "^1.80.6",
"sass-loader": "^16.0.3",
"style-loader": "^4.0.0",
"swc-loader": "^0.2.6",
"tgui-core": "^1.8.4",
"typescript": "5.8.2",
"tgui-core": "^2.0.5",
"typescript": "5.8.3",
"typescript-eslint": "^8.28.0",
"url-loader": "^4.1.1",
"webpack": "^5.96.1",
+6 -6
View File
@@ -1,18 +1,18 @@
{
"private": true,
"name": "tgui-bench",
"version": "5.0.3",
"version": "6.0.0",
"dependencies": {
"@fastify/static": "^8.0.2",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.1",
"common": "workspace:*",
"fastify": "^5.1.0",
"lodash": "^4.17.21",
"platform": "^1.3.6",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tgui": "workspace:*",
"tgui-core": "^1.8.4"
"tgui-core": "^2.0.5"
}
}
@@ -1,3 +1,4 @@
import React from 'react';
import { createRenderer } from 'tgui/renderer';
import { Button } from 'tgui-core/components';
@@ -14,7 +15,7 @@ export const SingleButtonWithCallback = () => {
};
export const ListOfButtons = () => {
const nodes: JSX.Element[] = [];
const nodes: React.JSX.Element[] = [];
for (let i = 0; i < 100; i++) {
const node = <Button key={i}>Hello world! {i}</Button>;
nodes.push(node);
@@ -23,7 +24,7 @@ export const ListOfButtons = () => {
};
export const ListOfButtonsWithCallback = () => {
const nodes: JSX.Element[] = [];
const nodes: React.JSX.Element[] = [];
for (let i = 0; i < 100; i++) {
const node = (
<Button key={i} onClick={() => undefined}>
@@ -36,7 +37,7 @@ export const ListOfButtonsWithCallback = () => {
};
export const ListOfButtonsWithIcons = () => {
const nodes: JSX.Element[] = [];
const nodes: React.JSX.Element[] = [];
for (let i = 0; i < 100; i++) {
const node = (
<Button key={i} icon={'arrow-left'}>
@@ -49,7 +50,7 @@ export const ListOfButtonsWithIcons = () => {
};
export const ListOfButtonsWithTooltips = () => {
const nodes: JSX.Element[] = [];
const nodes: React.JSX.Element[] = [];
for (let i = 0; i < 100; i++) {
const node = (
<Button key={i} tooltip={'Hello world!'}>
@@ -1,10 +1,11 @@
import React from 'react';
import { createRenderer } from 'tgui/renderer';
import { Box, Tooltip } from 'tgui-core/components';
const render = createRenderer();
export const ListOfTooltips = () => {
const nodes: JSX.Element[] = [];
const nodes: React.JSX.Element[] = [];
for (let i = 0; i < 100; i++) {
nodes.push(
+1 -1
View File
@@ -1,7 +1,7 @@
{
"private": true,
"name": "tgui-dev-server",
"version": "5.0.3",
"version": "6.0.0",
"type": "module",
"dependencies": {
"@types/ws": "^8.5.13",
+1 -1
View File
@@ -16,7 +16,7 @@ type ChatPanelTypes = {
};
export class ChatPanel extends Component<ChatPanelTypes> {
ref: RefObject<HTMLDivElement>;
ref: RefObject<HTMLDivElement | null>;
handleScrollTrackingChange: (value: any) => void;
state: { scrollTracking: boolean };
constructor(props) {
+4 -18
View File
@@ -13,18 +13,7 @@ import { selectChatPages, selectCurrentChatPage } from './selectors';
import type { Page } from './types';
const UnreadCountWidget = ({ value }: { value: number }) => (
<Box
style={{
fontSize: '0.7em',
borderRadius: '0.25em',
width: '1.7em',
lineHeight: '1.55em',
backgroundColor: 'crimson',
color: '#fff',
}}
>
{Math.min(value, 99)}
</Box>
<Box className="UnreadCount">{Math.min(value, 99)}</Box>
);
export const ChatTabs = (props) => {
@@ -39,12 +28,6 @@ export const ChatTabs = (props) => {
<Tabs.Tab
key={page.id}
selected={page === currentPage}
rightSlot={
!page.hideUnreadCount &&
page.unreadCount > 0 && (
<UnreadCountWidget value={page.unreadCount} />
)
}
onClick={() =>
dispatch(
changeChatPage({
@@ -54,6 +37,9 @@ export const ChatTabs = (props) => {
}
>
{page.name}
{!page.hideUnreadCount && page.unreadCount > 0 && (
<UnreadCountWidget value={page.unreadCount} />
)}
</Tabs.Tab>
))}
</Tabs>
+4 -4
View File
@@ -4,13 +4,13 @@
"version": "6.0.0",
"dependencies": {
"@types/node": "^22.9.0",
"@types/react": "^18.3.12",
"@types/react": "^19.1.0",
"common": "workspace:*",
"dompurify": "^3.2.4",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tgui": "workspace:*",
"tgui-core": "^1.8.4",
"tgui-core": "^2.0.5",
"tgui-dev-server": "workspace:*"
}
}
@@ -3,16 +3,10 @@
* SPDX-License-Identifier: MIT
*/
@use 'sass:color';
@use 'sass:math';
@use '~tgui/styles/base.scss';
@use '~tgui/styles/colors.scss';
$text-color: #abc6ec !default;
$color-bg-section: base.$color-bg-section !default;
.Chat {
color: $text-color;
color: var(--chat-text-color);
}
.Chat__badge {
@@ -21,11 +15,11 @@ $color-bg-section: base.$color-bg-section !default;
font-size: 0.7em;
padding: 0.2em 0.3em;
line-height: 1;
color: white;
color: hsl(0, 0%, 100%);
text-align: center;
white-space: nowrap;
vertical-align: middle;
background-color: crimson;
background-color: hsl(348, 83%, 47%);
border-radius: 10px;
transition: font-size 200ms ease-out;
@@ -55,25 +49,25 @@ $color-bg-section: base.$color-bg-section !default;
display: inline-block;
border-radius: 1em;
padding: 0 0.7em;
color: colors.$red;
background-color: $color-bg-section;
color: var(--color-red);
background-color: var(--color-section);
}
&:after {
content: '';
display: block;
margin-top: -0.75em;
border-bottom: math.div(1em, 6) solid colors.$red;
border-bottom: math.div(1em, 6) solid var(--color-red);
}
}
.Chat__highlight {
color: #000;
color: var(--color-black);
}
.Chat__highlight--restricted {
color: #fff;
background-color: #a00;
color: hsl(0, 0%, 100%);
background-color: hsl(0, 100%, 33.3%);
font-weight: bold;
}
@@ -83,7 +77,7 @@ $color-bg-section: base.$color-bg-section !default;
.ChatMessage--highlighted {
position: relative;
border-left: math.div(1em, 6) solid rgba(255, 221, 68);
border-left: math.div(1em, 6) solid hsl(50, 100%, 63.5%);
padding-left: 0.5em;
&:after {
@@ -93,7 +87,7 @@ $color-bg-section: base.$color-bg-section !default;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(255, 221, 68, 0.1);
background-color: hsla(50, 100%, 63.5%, 0.1);
// Make this click-through since this is an overlay
pointer-events: none;
}
@@ -5,14 +5,14 @@
@use 'sass:math';
$border-color: rgba(140, 140, 140, 0.5) !default;
.Ping {
position: relative;
padding: 0.125em 0.25em;
border: math.div(1em, 12) solid $border-color;
border-radius: 0.25em;
width: 3.75em;
padding: var(--space-xs) var(--space-sm);
border: var(--border-thickness-tiny) solid
hsl(from var(--color-border-primary) h 10 50 / 0.33);
border-radius: var(--border-radius-medium);
min-width: 4em;
max-width: 5em;
text-align: right;
user-select: 'none';
}
@@ -20,10 +20,11 @@ $border-color: rgba(140, 140, 140, 0.5) !default;
.Ping__indicator {
content: '';
position: absolute;
top: 0.5em;
left: 0.5em;
top: var(--space-m);
left: var(--space-m);
width: 0.5em;
height: 0.5em;
background-color: #888;
border-radius: 0.25em;
background-color: hsl(0, 0%, 53.3%);
border-radius: var(--border-radius-medium);
user-select: 'none';
}
@@ -0,0 +1,12 @@
.UnreadCount {
pointer-events: none;
position: absolute;
top: calc(-1 * var(--space-s));
right: calc(-1 * var(--space-s));
font-size: 0.65em;
padding: 0 var(--space-s);
border-radius: var(--border-radius-small);
line-height: 1.25em;
background-color: var(--color-red);
color: var(--color-white);
}
+11 -35
View File
@@ -6,12 +6,8 @@
@use 'sass:meta';
@use 'sass:color';
@use '~tgui/styles/colors.scss';
@use '~tgui/styles/base.scss' with (
$color-bg: hsl(0, 0%, 12.5%),
$color-bg-section: color.adjust(hsl(0, 0%, 12.5%), $lightness: -5%),
$color-bg-grad-spread: 0%
);
// Components
@use '~tgui-core/styles';
// Core styles
@include meta.load-css('~tgui/styles/reset.scss');
@@ -23,43 +19,23 @@
@include meta.load-css('~tgui/styles/atomic/outline.scss');
@include meta.load-css('~tgui/styles/atomic/text.scss');
// Components
@include meta.load-css('~tgui-core/styles/components/BlockQuote.scss');
@include meta.load-css('~tgui-core/styles/components/Button.scss');
@include meta.load-css('~tgui-core/styles/components/ColorBox.scss');
@include meta.load-css('~tgui-core/styles/components/Dialog.scss');
@include meta.load-css('~tgui-core/styles/components/Dimmer.scss');
@include meta.load-css('~tgui-core/styles/components/Divider.scss');
@include meta.load-css('~tgui-core/styles/components/Dropdown.scss');
@include meta.load-css('~tgui-core/styles/components/Flex.scss');
@include meta.load-css('~tgui-core/styles/components/Icon.scss');
@include meta.load-css('~tgui-core/styles/components/ImageButton.scss');
@include meta.load-css('~tgui-core/styles/components/Input.scss');
@include meta.load-css('~tgui-core/styles/components/Knob.scss');
@include meta.load-css('~tgui-core/styles/components/LabeledList.scss');
@include meta.load-css('~tgui-core/styles/components/MenuBar.scss');
@include meta.load-css('~tgui-core/styles/components/Modal.scss');
@include meta.load-css('~tgui-core/styles/components/NoticeBox.scss');
@include meta.load-css('~tgui-core/styles/components/NumberInput.scss');
@include meta.load-css('~tgui-core/styles/components/ProgressBar.scss');
@include meta.load-css('~tgui-core/styles/components/RoundGauge.scss');
@include meta.load-css('~tgui-core/styles/components/Section.scss');
@include meta.load-css('~tgui-core/styles/components/Slider.scss');
@include meta.load-css('~tgui-core/styles/components/Stack.scss');
@include meta.load-css('~tgui-core/styles/components/Table.scss');
@include meta.load-css('~tgui-core/styles/components/Tabs.scss');
@include meta.load-css('~tgui-core/styles/components/TextArea.scss');
@include meta.load-css('~tgui-core/styles/components/Tooltip.scss');
// Components specific to tgui-panel
@include meta.load-css('./components/Chat.scss');
@include meta.load-css('./components/Ping.scss');
@include meta.load-css('./components/Notifications.scss');
@include meta.load-css('./components/UnreadCount.scss');
// Layouts
@include meta.load-css('~tgui/styles/layouts/Layout.scss');
// @include meta.load-css('~tgui/styles/layouts/TitleBar.scss');
@include meta.load-css('~tgui/styles/layouts/Window.scss');
// tgchat styles
@include meta.load-css('./tgchat/chat-dark.scss');
:root {
--chat-text-color: hsl(210, 50%, 80%);
--color-base: hsl(0, 0%, 12.5%);
--color-section: hsl(from var(--color-base) h s calc(l - 4.2));
--base-gradient-spread: 0;
}
@@ -27,19 +27,25 @@ img.icon {
}
a {
color: hsl(202, 49%, 44%);
}
a.visited {
color: hsl(272, 100%, 45%);
}
a:visited {
color: hsl(272, 100%, 45%);
}
a.popt {
cursor: var(--cursor-pointer);
color: var(--color-hyperlink);
transition: color var(--transition-time-medium);
text-decoration: none;
&:hover {
color: hsl(from var(--color-hyperlink) h s calc(l + var(--adjust-hover)));
}
}
a.visited,
a:visited {
color: var(--color-hyperlink-visited);
&:hover {
color: hsl(
from var(--color-hyperlink-visited) h s calc(l + var(--adjust-hover))
);
}
}
/* POPUPS */
@@ -11,7 +11,7 @@ body {
padding: 0;
margin: 0;
height: 100%;
color: hsl(0, 0%, 0%);
color: var(--color-black);
}
body {
@@ -45,19 +45,20 @@ img.icon {
}
a {
color: hsl(240, 100%, 50%);
}
a.visited {
color: hsl(300, 100%, 50%);
color: hsl(from var(--color-hyperlink) h s calc(l - 40));
&:hover {
color: hsl(from var(--color-hyperlink) h s calc(l - 20));
}
}
a.visited,
a:visited {
color: hsl(300, 100%, 50%);
}
color: hsl(from var(--color-hyperlink-visited) h s calc(l - 40));
a.popt {
text-decoration: none;
&:hover {
color: hsl(from var(--color-hyperlink-visited) h s calc(l - 20));
}
}
/* POPUPS */
@@ -277,7 +278,7 @@ h6 {
h1.alert,
h2.alert {
color: hsl(0, 0%, 0%);
color: var(--color-black);
}
em {
@@ -412,7 +413,7 @@ img.icon.bigicon {
.binarysay {
font-style: italic;
color: hsl(114, 87%, 41%);
background-color: hsl(0, 0%, 0%);
background-color: var(--color-black);
display: inline-block;
}
@@ -507,7 +508,7 @@ img.icon.bigicon {
h1.alert,
h2.alert {
color: hsl(0, 0%, 0%);
color: var(--color-black);
}
.userdanger {
@@ -577,12 +578,12 @@ h2.alert {
}
.minoralert {
color: hsl(0, 0%, 0%);
color: var(--color-black);
font-size: 125%;
}
.priorityannounce {
color: hsl(0, 0%, 0%);
color: var(--color-black);
font-weight: bold;
font-size: 225%;
}
@@ -27,19 +27,25 @@ img.icon {
}
a {
color: hsl(202, 49%, 44%);
}
a.visited {
color: hsl(272, 100%, 45%);
}
a:visited {
color: hsl(272, 100%, 45%);
}
a.popt {
cursor: var(--cursor-pointer);
color: var(--color-hyperlink);
transition: color var(--transition-time-medium);
text-decoration: none;
&:hover {
color: hsl(from var(--color-hyperlink) h s calc(l + var(--adjust-hover)));
}
}
a.visited,
a:visited {
color: var(--color-hyperlink-visited);
&:hover {
color: hsl(
from var(--color-hyperlink-visited) h s calc(l + var(--adjust-hover))
);
}
}
/* POPUPS */
@@ -45,19 +45,20 @@ img.icon {
}
a {
color: hsl(240, 100%, 50%);
}
a.visited {
color: hsl(300, 100%, 50%);
color: hsl(from var(--color-hyperlink) h s calc(l - 40));
&:hover {
color: hsl(from var(--color-hyperlink) h s calc(l - 20));
}
}
a.visited,
a:visited {
color: hsl(300, 100%, 50%);
}
color: hsl(from var(--color-hyperlink-visited) h s calc(l - 40));
a.popt {
text-decoration: none;
&:hover {
color: hsl(from var(--color-hyperlink-visited) h s calc(l - 20));
}
}
/* POPUPS */
@@ -6,91 +6,28 @@
@use 'sass:color';
@use 'sass:meta';
@use '~tgui/styles/colors.scss' with (
$primary: hsl(0, 0%, 100%),
$bg-lightness: -25%,
$fg-lightness: -10%,
$label: hsl(0, 0%, 23.1%),
// Makes button look actually grey due to weird maths.
$grey: hsl(0, 0%, 100%),
// Commenting out color maps will adjust all colors based on the lightness
// settings above, but will add extra 10KB to the theme.
// $fg-map-keys: (),
// $bg-map-keys: (),
);
@use '~tgui/styles/base.scss' with (
$color-fg: hsl(0, 0%, 0%),
$color-bg: hsl(0, 0%, 93.3%),
$color-bg-grad-spread: 0%
);
.theme-light:root {
--chat-text-color: var(--color-black);
// A fat warning to anyone who wants to use this: this only half works.
// It was made almost purely for the nuke ui, and requires a good amount of manual hacks to get it working as intended.
.theme-light {
// Atomic classes
@include meta.load-css('~tgui/styles/atomic/color.scss');
// Base
--color-base: hsl(0, 0%, 93%);
--color-section: var(--color-white);
--color-text: var(--color-black);
--color-label: hsl(0, 0%, 33%);
--color-action: hsl(0, 0%, 90%);
--color-scrollbar-thumb: var(--color-light-gray);
--primary-lightness: 60%;
--primary-saturation: 60%;
--border-primary-alpha: 0.66;
// Components
@include meta.load-css(
'~tgui-core/styles/components/Tabs',
$with: (
'text-color': rgba(0, 0, 0, 0.5),
'color-default': rgba(0, 0, 0, 1),
'tab-color-selected': rgba(0, 0, 0, 0.125),
'tab-color-hovered': rgba(0, 0, 0, 0.075)
)
);
--button-background-selected: hsl(from var(--color-primary) h 100 l);
--button-background-caution: hsl(27.5, 90%, 38%);
--button-background-danger: hsl(60, 100%, 30%);
--tab-color-selected: var(--color-black);
--input-background: var(--color-base);
--tooltip-background-lightness: 90;
@include meta.load-css(
'~tgui-core/styles/components/Section',
$with: ('background-color': hsl(0, 0%, 100%))
);
@include meta.load-css(
'~tgui-core/styles/components/Button',
$with: (
'color-default': hsl(0, 0%, 73.3%),
'color-disabled': hsl(0, 0%, 21.2%),
'color-selected': hsl(204, 94%, 35.3%),
'color-caution': hsl(28, 91%, 38.2%),
'color-danger': hsl(62, 100%, 30.2%),
'color-transparent-text': rgba(0, 0, 0, 0.5)
)
);
@include meta.load-css(
'~tgui-core/styles/components/Input',
$with: (
'border-color': colors.fg(colors.$label),
'background-color': hsl(0, 0%, 90.2%)
)
);
@include meta.load-css('~tgui-core/styles/components/NumberInput');
@include meta.load-css('~tgui-core/styles/components/TextArea');
@include meta.load-css('~tgui-core/styles/components/Knob');
@include meta.load-css('~tgui-core/styles/components/Slider');
@include meta.load-css('~tgui-core/styles/components/ProgressBar');
// Components specific to tgui-panel
@include meta.load-css(
'../components/Chat.scss',
$with: ('text-color': hsl(0, 0%, 0%))
);
// Layouts
@include meta.load-css(
'~tgui/styles/layouts/Layout.scss',
$with: ('scrollbar-color-multiplier': -1)
);
@include meta.load-css('~tgui/styles/layouts/Window.scss');
@include meta.load-css(
'~tgui/styles/layouts/TitleBar.scss',
$with: (
'text-color': rgba(0, 0, 0, 0.75),
'background-color': base.$color-bg,
'shadow-color-core': rgba(0, 0, 0, 0.25)
)
);
// tgchat styles
// Chat styles
@include meta.load-css('../tgchat/chat-light.scss');
}
@@ -6,37 +6,11 @@
@use 'sass:color';
@use 'sass:meta';
@use '~tgui/styles/colors.scss';
@use '~tgui/styles/base.scss';
// A fat warning to anyone who wants to use this: this only half works.
// It was made almost purely for the nuke ui, and requires a good amount of manual hacks to get it working as intended.
.theme-vchatdark {
// Atomic classes
@include meta.load-css('~tgui/styles/atomic/color.scss');
--chat-text-color: var(--color-white);
// Components
@include meta.load-css('~tgui-core/styles/components/Tabs.scss');
@include meta.load-css('~tgui-core/styles/components/Section.scss');
@include meta.load-css('~tgui-core/styles/components/Button.scss');
@include meta.load-css('~tgui-core/styles/components/Input.scss');
@include meta.load-css('~tgui-core/styles/components/NumberInput.scss');
@include meta.load-css('~tgui-core/styles/components/TextArea.scss');
@include meta.load-css('~tgui-core/styles/components/Knob.scss');
@include meta.load-css('~tgui-core/styles/components/Slider.scss');
@include meta.load-css('~tgui-core/styles/components/ProgressBar.scss');
// Components specific to tgui-panel
@include meta.load-css(
'../components/Chat.scss',
$with: ('text-color': hsl(0, 0%, 100%))
);
// Layouts
@include meta.load-css('~tgui/styles/layouts/Layout.scss');
@include meta.load-css('~tgui/styles/layouts/Window.scss');
@include meta.load-css('~tgui/styles/layouts/TitleBar.scss');
// tgchat styles
// Chat styles
@include meta.load-css('../tgchat/chat-vchatdark.scss');
}
@@ -6,91 +6,28 @@
@use 'sass:color';
@use 'sass:meta';
@use '~tgui/styles/colors.scss' with (
$primary: hsl(0, 0%, 100%),
$bg-lightness: -25%,
$fg-lightness: -10%,
$label: hsl(0, 0%, 23.1%),
// Makes button look actually grey due to weird maths.
$grey: hsl(0, 0%, 100%),
// Commenting out color maps will adjust all colors based on the lightness
// settings above, but will add extra 10KB to the theme.
// $fg-map-keys: (),
// $bg-map-keys: (),
);
@use '~tgui/styles/base.scss' with (
$color-fg: hsl(0, 0%, 0%),
$color-bg: hsl(0, 0%, 93.3%),
$color-bg-grad-spread: 0%
);
.theme-vchatlight:root {
--chat-text-color: var(--color-black);
// A fat warning to anyone who wants to use this: this only half works.
// It was made almost purely for the nuke ui, and requires a good amount of manual hacks to get it working as intended.
.theme-vchatlight {
// Atomic classes
@include meta.load-css('~tgui/styles/atomic/color.scss');
// Base
--color-base: hsl(0, 0%, 93%);
--color-section: var(--color-white);
--color-text: var(--color-black);
--color-label: hsl(0, 0%, 33%);
--color-action: hsl(0, 0%, 90%);
--color-scrollbar-thumb: var(--color-light-gray);
--primary-lightness: 60%;
--primary-saturation: 60%;
--border-primary-alpha: 0.66;
// Components
@include meta.load-css(
'~tgui-core/styles/components/Tabs',
$with: (
'text-color': rgba(0, 0, 0, 0.5),
'color-default': rgba(0, 0, 0, 1),
'tab-color-selected': rgba(0, 0, 0, 0.125),
'tab-color-hovered': rgba(0, 0, 0, 0.075)
)
);
--button-background-selected: hsl(from var(--color-primary) h 100 l);
--button-background-caution: hsl(27.5, 90%, 38%);
--button-background-danger: hsl(60, 100%, 30%);
--tab-color-selected: var(--color-black);
--input-background: var(--color-base);
--tooltip-background-lightness: 90;
@include meta.load-css(
'~tgui-core/styles/components/Section',
$with: ('background-color': hsl(0, 0%, 100%))
);
@include meta.load-css(
'~tgui-core/styles/components/Button',
$with: (
'color-default': hsl(0, 0%, 73.3%),
'color-disabled': hsl(0, 0%, 21.2%),
'color-selected': hsl(204, 94%, 35.3%),
'color-caution': hsl(28, 91%, 38.2%),
'color-danger': hsl(62, 100%, 30.2%),
'color-transparent-text': rgba(0, 0, 0, 0.5)
)
);
@include meta.load-css(
'~tgui-core/styles/components/Input',
$with: (
'border-color': colors.fg(colors.$label),
'background-color': hsl(0, 0%, 90.2%)
)
);
@include meta.load-css('~tgui-core/styles/components/NumberInput');
@include meta.load-css('~tgui-core/styles/components/TextArea');
@include meta.load-css('~tgui-core/styles/components/Knob');
@include meta.load-css('~tgui-core/styles/components/Slider');
@include meta.load-css('~tgui-core/styles/components/ProgressBar');
// Components specific to tgui-panel
@include meta.load-css(
'../components/Chat.scss',
$with: ('text-color': hsl(0, 0%, 0%))
);
// Layouts
@include meta.load-css(
'~tgui/styles/layouts/Layout.scss',
$with: ('scrollbar-color-multiplier': -1)
);
@include meta.load-css('~tgui/styles/layouts/Window.scss');
@include meta.load-css(
'~tgui/styles/layouts/TitleBar.scss',
$with: (
'text-color': rgba(0, 0, 0, 0.75),
'background-color': base.$color-bg,
'shadow-color-core': rgba(0, 0, 0, 0.25)
)
);
// tgchat styles
// Chat styles
@include meta.load-css('../tgchat/chat-vchatlight.scss');
}
+26 -19
View File
@@ -26,8 +26,6 @@ import { byondMessages } from './timers';
type ByondOpen = {
channel: Channel;
minimumWidth: number;
minimumHeight: number;
};
type ByondProps = {
@@ -35,6 +33,7 @@ type ByondProps = {
minimumHeight: number;
minimumWidth: number;
lightMode: BooleanLike;
scale: BooleanLike;
};
const ROWS: Record<keyof typeof WindowSize, number> = {
@@ -51,6 +50,9 @@ export function TguiSay() {
const channelIterator = useRef(new ChannelIterator());
const chatHistory = useRef(new ChatHistory());
const messages = useRef(byondMessages);
const scale = useRef(true);
const minimumHeight = useRef(WindowSize.Small);
const minimumWidth = useRef(WindowSize.Width);
// I initially wanted to make these an object or a reducer, but it's not really worth it.
// You lose the granulatity and add a lot of boilerplate.
@@ -60,12 +62,9 @@ export function TguiSay() {
>(null);
const [size, setSize] = useState(WindowSize.Small);
const [maxLength, setMaxLength] = useState(4096);
const [minimumHeight, setMinimumHeight] = useState(WindowSize.Small);
const [minimumWidth, setMinimumWidth] = useState(WindowSize.Width);
const [lightMode, setLightMode] = useState(false);
const [position, setPosition] = useState([window.screenX, window.screenY]);
const [value, setValue] = useState('');
const [rescale, setRescale] = useState(false);
function handleArrowKeys(direction: KEY.PageUp | KEY.PageDown): void {
const chat = chatHistory.current;
@@ -113,7 +112,7 @@ export function TguiSay() {
function handleClose(): void {
innerRef.current?.blur();
windowClose();
windowClose(minimumWidth.current, minimumHeight.current, scale.current);
setTimeout(() => {
chatHistory.current.reset();
@@ -294,6 +293,7 @@ export function TguiSay() {
}
function handleOpen(data: ByondOpen): void {
setSize(minimumHeight.current);
setTimeout(() => {
innerRef.current?.focus();
}, 1);
@@ -306,34 +306,33 @@ export function TguiSay() {
}
setButtonContent(iterator.current());
windowOpen(iterator.current());
setRescale(true);
windowOpen(
iterator.current(),
minimumWidth.current,
minimumHeight.current,
scale.current,
);
}
function handleProps(data: ByondProps): void {
setMaxLength(data.maxLength);
setMinimumHeight(data.minimumHeight);
const minWidth = clamp(
data.minimumWidth,
WindowSize.Width,
WindowSize.MaxWidth,
);
setMinimumWidth(minWidth);
minimumHeight.current = data.minimumHeight;
minimumWidth.current = minWidth;
setLightMode(!!data.lightMode);
scale.current = !!data.scale;
}
function unloadChat(): void {
setCurrentPrefix(null);
setButtonContent(channelIterator.current.current());
setValue('');
setRescale(false);
}
useEffect(() => {
setSize(minimumHeight);
windowSet(minimumWidth, minimumHeight);
}, [rescale]);
/** Subscribe to Byond messages */
useEffect(() => {
Byond.subscribeTo('props', handleProps);
@@ -353,11 +352,11 @@ export function TguiSay() {
} else {
newSize = WindowSize.Small;
}
newSize = clamp(newSize, minimumHeight, WindowSize.Max);
newSize = clamp(newSize, minimumHeight.current, WindowSize.Max);
if (size !== newSize) {
setSize(newSize);
windowSet(minimumWidth, newSize);
windowSet(minimumWidth.current, newSize, scale.current);
}
}, [value]);
@@ -370,11 +369,19 @@ export function TguiSay() {
<>
<div
className={`window window-${theme} window-${size}`}
style={{
zoom: scale.current ? '' : `${100 / window.devicePixelRatio}%`,
}}
onMouseDown={dragStartHandler}
>
{!lightMode && <div className={`shine shine-${theme}`} />}
</div>
<div className={classes(['content', lightMode && 'content-lightMode'])}>
<div
className={classes(['content', lightMode && 'content-lightMode'])}
style={{
zoom: scale.current ? '' : `${100 / window.devicePixelRatio}%`,
}}
>
<button
className={`button button-${theme}`}
onClick={handleIncrementChannel}
+33 -14
View File
@@ -5,8 +5,13 @@ import { RADIO_PREFIXES, WindowSize } from './constants';
* Once byond signals this via keystroke, it
* ensures window size, visibility, and focus.
*/
export function windowOpen(channel: Channel): void {
setWindowVisibility(true);
export function windowOpen(
channel: Channel,
width: number,
height: number,
scale: boolean,
): void {
setWindowVisibility(true, width, height, scale);
Byond.sendMessage('open', { channel });
}
@@ -14,8 +19,12 @@ export function windowOpen(channel: Channel): void {
* Resets the state of the window and hides it from user view.
* Sending "close" logs it server side.
*/
export function windowClose(): void {
setWindowVisibility(false);
export function windowClose(
width: number,
height: number,
scale: boolean,
): void {
setWindowVisibility(false, width, height, scale);
Byond.winset('map', {
focus: true,
});
@@ -28,23 +37,33 @@ export function windowClose(): void {
export function windowSet(
width = WindowSize.Width,
size = WindowSize.Small,
scale: boolean,
): void {
const sizeStr = `${width}x${size}`;
const pixelRatio = scale ? window.devicePixelRatio : 1;
Byond.winset('tgui_say.browser', {
size: sizeStr,
});
const sizeStr = `${width * pixelRatio}x${size * pixelRatio}`;
Byond.winset('tgui_say', {
size: sizeStr,
Byond.winset(null, {
'tgui_say.size': sizeStr,
'tgui_say.browser.size': sizeStr,
});
}
/** Helper function to set window size and visibility */
function setWindowVisibility(visible: boolean): void {
Byond.winset('tgui_say', {
'is-visible': visible,
size: `${WindowSize.Width}x${WindowSize.Small}`,
function setWindowVisibility(
visible: boolean,
width: number,
height: number,
scale: boolean,
): void {
const pixelRatio = scale ? window.devicePixelRatio : 1;
const sizeStr = `${width * pixelRatio}x${height * pixelRatio}`;
Byond.winset(null, {
'tgui_say.is-visible': visible,
'tgui_say.size': sizeStr,
'tgui_say.browser.size': sizeStr,
});
}
+5 -5
View File
@@ -3,12 +3,12 @@
"name": "tgui-say",
"version": "1.0.0",
"dependencies": {
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.1",
"common": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tgui": "workspace:*",
"tgui-core": "^1.8.4"
"tgui-core": "^2.0.5"
}
}
+6 -18
View File
@@ -22,10 +22,7 @@
.shine {
animation: shine 15s linear infinite;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
inset: 0;
background-size: 150% 150%;
}
@@ -169,19 +166,10 @@
margin: 0.1rem 0 0 0.4rem;
outline: none;
resize: none;
&::-webkit-scrollbar {
width: 0.8rem;
}
&::-webkit-scrollbar-track {
background: color.scale(
scrollbar-width: thin;
scrollbar-color: color.scale(
colors.$button,
$lightness: -25% * colors.$scrollbar-color-multiplier
);
}
&::-webkit-scrollbar-thumb {
background: color.scale(
colors.$button,
$lightness: 10% * colors.$scrollbar-color-multiplier
);
}
$lightness: 20% * colors.$scrollbar-color-multiplier
)
transparent;
}
+29
View File
@@ -0,0 +1,29 @@
<svg width="489" height="648" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" opacity=".33" focusable="false" data-prefix="fas" data-icon="crow" class="svg-inline--fa fa-crow fa-w-20" role="img">
<g>
<title>Layer 1</title>
<g transform="rotate(7.40895 373.485 375.045)" stroke="null" id="svg_1">
<switch stroke="null" transform="translate(3 -8) translate(-1 -2) translate(-13 65) translate(6.21294 5.46086) translate(30.8511 9.57447) translate(9.57447 1.06383) translate(0 -1.06383) translate(-14.7826 -12.1739) translate(81.7391 35.6522) translate(0.869565 1.73913) translate(-186.28 -29.1396) translate(10.4348 18.2609) translate(32.1739 -12.1739) translate(-15.6522 0) translate(32.3077 -18.4615) translate(-9.24131 5.33599) translate(-24.6154 -15.3846) translate(56.9231 3.07692) translate(-189.231 84.6154) translate(210.769 -10.7692) translate(400 253) translate(-77 -57) translate(271.75 0) translate(0 192.758) translate(194.75 141.242) scale(3.89231 3.89231) translate(-194.75 -141.242) translate(64.7362 -2.3592) scale(0.543589 0.543589) translate(-64.7362 2.3592) translate(97.1787 23.2502) scale(1.34622 1.34622) translate(-97.1787 -23.2502) translate(38.0044 239.694) scale(1.1325 1.1325) translate(-38.0044 -239.694)">
<foreignObject stroke="null" id="svg_2" requiredExtensions="http://ns.adobe.com/AdobeIllustrator/10.0/" x="0" y="0" width="1" height="1"/>
<g stroke="null" id="svg_6">
<g stroke="null" id="svg_8">
<path stroke="null" id="svg_10" d="m76.3,55.6l2.2,8.1c1.3,4.8 -1.1,9.8 -5.7,11.8c-7.2,3.1 -14.8,4.7 -22.6,4.7c-7.9,0 -15.4,-1.6 -22.5,-4.7c-4.6,-2 -7,-7 -5.7,-11.8l2.2,-8.2c-18.8,3.4 -21.7,10.4 -21.7,15.4c0,6.7 1.8,23.8 47.5,23.8s47.5,-17.1 47.5,-23.8c0,-5 -2.8,-12 -21.2,-15.3z"/>
<path stroke="null" id="svg_11" d="m30,69.9c12.7,5.6 27.4,5.6 40.2,0c1.8,-0.8 2.8,-2.7 2.3,-4.6l-6.3,-23.7c-1.9,-7.3 -1.7,-15 0.6,-22.1c1.2,-3.7 3.1,-7.2 5.6,-10.2c1.5,-1.8 -0.3,-4.4 -2.5,-3.7l-6.2,2c-5.2,1.7 -9.8,4.7 -13.5,8.7l-6.5,7.1c-4.3,4.6 -7.4,10.3 -9,16.4l-6.8,25.6c-0.6,1.8 0.4,3.7 2.1,4.5z"/>
</g>
</g>
</switch>
<text stroke="null" id="svg_12" x="266.18396" y="365.42306" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif" transform="matrix(3.22573 0 0 3.22573 -386.442 -454.691)">Created by Alice Design</text>
<text stroke="null" id="svg_13" x="266.18396" y="370.42306" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif" transform="matrix(3.22573 0 0 3.22573 -386.442 -454.691)">from the Noun Project</text>
</g>
<rect transform="rotate(12 282.996 345.218)" fill="currentColor" x="269.76986" y="307.47567" width="26.45161" height="75.48388" id="svg_3" rx="10" stroke="null"/>
<rect transform="rotate(12 173.308 320.223)" fill="currentColor" x="160.08247" y="282.4807" width="26.45161" height="75.48388" id="svg_4" rx="10" stroke="null"/>
<rect transform="rotate(45 189.324 401.377)" fill="currentColor" x="176.09766" y="372.9915" width="26.45161" height="56.76909" id="svg_5" rx="10" stroke="null"/>
<rect transform="rotate(-45 188.111 426.09)" fill="currentColor" x="174.88484" y="397.70546" width="26.45161" height="56.76909" id="svg_7" rx="10" stroke="null"/>
<path fill="currentColor" stroke="null" opacity="NaN" d="m204.34782,457.91306l197.39131,-1.39132" id="svg_9"/>
<path fill="none" stroke="null" opacity="NaN" d="m263.47826,482.26088c123.47826,-42.6087 103.47826,-89.56522 103.47826,-90.08697" id="svg_15"/>
<path fill="none" stroke="null" opacity="NaN" d="m770.58698,382.08695" id="svg_17"/>
<g>
<path transform="rotate(10.5743 198.754 509.675)" stroke="null" d="m349.39497,519.23199c-22.92157,-5.23171 -37.31453,-28.13599 -32.08397,-51.05641c0.85044,-3.72212 -1.47848,-7.42926 -5.20175,-8.2797c-3.72097,-0.84814 -7.42926,1.47963 -8.28085,5.2029c-2.80945,12.30834 -1.34365,24.61208 3.41444,35.35552c-0.32151,0.22586 -0.63956,0.46786 -0.92765,0.7571c-28.75481,28.75365 -66.95435,44.58937 -107.56116,44.58937c-40.60682,0 -78.8052,-15.83571 -107.55886,-44.58937c-0.28809,-0.28809 -0.60499,-0.53009 -0.92765,-0.75825c4.75694,-10.74114 6.22158,-23.04602 3.41213,-35.35437c-0.85044,-3.72327 -4.55643,-6.05334 -8.2797,-5.2029c-3.72327,0.84929 -6.05219,4.55643 -5.2029,8.2797c5.23171,22.92041 -9.1601,45.8247 -32.08051,51.05641c-3.72327,0.84929 -6.05219,4.55643 -5.2029,8.27854c0.73175,3.20471 3.58038,5.37691 6.73438,5.37691c0.50934,0 1.0279,-0.05647 1.54416,-0.17401c13.10232,-2.99152 24.09236,-10.34818 31.8051,-20.17895c31.17937,30.38079 72.19182,47.0946 115.75443,47.0946c43.56492,0 84.57737,-16.71266 115.75558,-47.0946c7.71274,9.83077 18.70278,17.18858 31.80741,20.17895c0.51741,0.11869 1.03482,0.17401 1.54416,0.17401c3.15285,0 6.00264,-2.1722 6.73438,-5.37691c0.8539,-3.72212 -1.47617,-7.42926 -5.19829,-8.27854z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

+24
View File
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 400 500" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
<defs>
<bx:grid x="0" y="0" width="50" height="50"/>
</defs>
<path style="stroke-width: 3px; fill: none; stroke: rgb(0, 0, 0); visibility: hidden;" d="M 300 200 C 350 50 300 100 250 150 M 250 150 C 225 140 175 140 150 150 C 100 100 50 50 100 200 L 100 200 C 0 400 400 400 300 200" bx:origin="0.5 0.527342"/>
<path style="paint-order: fill; fill: none; stroke: rgb(0, 0, 0); stroke-width: 9px; stroke-linecap: round;" d="M 150 273.803 C 150 308.732 200 308.732 200 273.803 C 200 308.732 250 308.732 250 273.803"/>
<ellipse style="fill: rgb(255, 132, 132);" cx="200" cy="260" rx="23.683" ry="15.071"/>
<circle style="stroke: rgb(0, 0, 0);" cx="150" cy="215" r="15.842"/>
<circle style="stroke: rgb(0, 0, 0);" cx="250" cy="215" r="15.842"/>
<g>
<title>Whiskers</title>
<path style="stroke: rgb(0, 0, 0); fill: none; stroke-width: 3px;" d="M 289.443 237.208 C 300 230.842 328.768 218.572 350 221.856"/>
<path style="stroke: rgb(0, 0, 0); fill: none; stroke-width: 3px;" d="M 290.469 265.901 C 301.026 259.535 329.794 247.265 351.027 250.549" transform="matrix(0.965947, 0.258739, -0.258739, 0.965947, 77.664281, -74.2061)"/>
<path style="stroke: rgb(0, 0, 0); fill: none; stroke-width: 3px;" d="M 290.469 292.436 C 301.026 286.07 329.794 273.8 351.027 277.084" transform="matrix(0.866067, 0.499928, -0.499928, 0.866067, 185.181275, -122.248912)"/>
<path style="stroke: rgb(0, 0, 0); fill: none; stroke-width: 3px;" d="M 52.052 221.307 C 62.609 227.673 91.377 239.943 112.609 236.659" transform="matrix(-1, 0, 0, -1, 164.660999, 458.514526)"/>
<path style="stroke: rgb(0, 0, 0); fill: none; stroke-width: 3px;" d="M 51.026 250.001 C 61.583 256.367 90.351 268.637 111.584 265.353" transform="matrix(-0.965947, 0.258739, -0.258739, -0.965947, 226.583405, 486.081802)"/>
<path style="stroke: rgb(0, 0, 0); fill: none; stroke-width: 3px;" d="M 51.025 276.535 C 61.582 282.901 90.35 295.172 111.583 291.888" transform="matrix(-0.866067, 0.499928, -0.499928, -0.866067, 293.941085, 490.223292)"/>
</g>
<path style="fill: none; stroke-width: 3px; stroke: rgb(0, 0, 0); visibility: hidden;" d="M 100 200 C 0 400 400 400 300 200 C 350 50 300 100 250 150 C 225 140 175 140 150 150 C 100 100 50 50 100 200 Z" bx:origin="0.5 0.527342"/>
<path style="fill: none; stroke-width: 3px; stroke: rgb(0, 0, 0); visibility: hidden;" d="M 150 150 C 100 100 50 50 100 200 M 300 200 C 350 50 300 100 250 150" bx:origin="0.5 0.527342">
<title>just ears</title>
</path>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@@ -0,0 +1 @@
<svg width="210mm" height="297mm" viewBox="0 0 210 297" xmlns="http://www.w3.org/2000/svg"><path d="M102 80h3v137h-3z"/><path d="M37 145v3h137v-3z"/><path d="M37 145h5a65 65 0 0 1 60-61 65 65 0 0 1 63 36 66 66 0 0 1-33 90 68 68 0 0 1-91-38 70 70 0 0 0 130 1 71 71 0 0 0-41-93 72 72 0 0 0-98 65h5z"/><path d="M105 145v1c-1 1-4 0-4-1-3-4 1-9 4-10 7-3 15 3 17 10 4 12-6 24-17 27-18 4-35-10-39-28-5-25 15-48 39-52 34-6 64 21 69 53" fill="none" stroke="#000" stroke-width=".26458"/><path d="M106 149v-1c1-2 4 0 5 1 2 4-1 8-5 10-7 3-15-3-17-10-4-13 6-25 18-27 18-5 35 10 38 27 5 26-15 49-39 53-34 6-64-21-69-54" fill="none" stroke="#000" stroke-width=".26458"/><path d="M102 148h1c2 2 0 4-1 5-4 2-8-1-10-5-3-7 3-15 10-17 12-4 24 6 27 18 4 18-10 35-27 38-25 5-48-15-53-39-6-33 21-63 53-68" fill="none" stroke="#000" stroke-width=".26458"/><path d="M105 145h-1c-2-2 0-4 1-5 4-2 9 1 10 5 3 7-3 15-10 18-13 4-25-6-28-18-5-19 10-37 28-41 26-6 51 15 55 41 7 35-21 66-55 72" fill="none" stroke="#000" stroke-width=".26458"/><circle cx="18.9" cy="108.5" r=".1" stroke="#000" stroke-width=".3"/><circle cx="18.9" cy="108.5" r=".1" stroke="#000" stroke-width=".3"/><path d="M127 143c-3-6-9-11-16-12l-4-1h-2v-8h1l12-1c7 2 12 5 17 10a34 34 0 0 1 9 14h-16zM105 194v-7l1-1c6-2 11-5 15-9a31 31 0 0 0 8-28v-1h16v16c-3 18-18 33-38 37l-2 1zM91 202a63 63 0 0 1-54-52v-1l6-1h6v2c4 15 14 27 26 34 6 3 11 4 18 4l9-1v15H91zM66 143c-1-6 0-13 2-19a49 49 0 0 1 34-31v12h-2l-8 4c-9 6-15 15-16 25a41 41 0 0 0 1 11H67zM95 172a32 32 0 0 1-21-12c-3-3-5-8-6-11v-1h10l1 2c1 2 2 5 5 7 3 3 6 5 10 6l5 1h3v8h-7zM105 167v-4l2-1c4-2 8-6 9-10v-4h7v3c-1 8-5 14-13 18l-5 2v-4z"/><path d="m115 144-4-4-5-1-1 1v-5h7c3 0 5 2 7 5l3 5h-6zM100 159c-4-1-8-4-10-8v-3h2v1l4 4h6v3c0 4 0 3-2 3zM105 153v-5l1 1 2-1 2 1 1 3-2 5-4 2v-6zM101 144c-1-1-1-4 1-6v-1 8l-1-1zM88 144l1-6 3-6 8-8c2-1 2-1 2 3v4h-1c-5 2-10 8-10 13v1h-3zM160 144a55 55 0 0 0-18-31c-7-5-15-9-23-10l-13 1h-1V92h17a60 60 0 0 1 44 32c3 6 5 13 5 19v2h-11zM117 214c22-8 39-26 43-48 1-5 2-12 1-16v-2h10v2a70 70 0 0 1-15 42l-10 9c-8 7-18 11-29 13-2 1-3 1 0 0zM42 144v-4a66 66 0 0 1 23-41l-1 1-6 8a57 57 0 0 0-10 36l1 1h-7Z"/><path d="M102 243a99 99 0 0 0 100-99 97 97 0 0 0-63-89A99 99 0 0 0 35 77a98 98 0 0 0 30 158c13 6 26 8 37 8zm0-11a88 88 0 0 1-85-88 86 86 0 0 1 53-77 88 88 0 0 1 94 16 87 87 0 0 1 2 124 87 87 0 0 1-64 25z"/><path d="M166 148h-5l2 53-57-52 58 60 4 4v-6l3-59h-5zM166 145h5l-3-61v-6l-4 5-59 62 58-55-2 55h5z"/><circle cx="41" cy="148" r=".4"/><path d="M43 148h-5l3 60v6l4-4 58-61-57 53 2-54h-5zM45 145h4l-1-30-2-28 60 58-60-62-3-3v4l-2 31-1 30h5z"/></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

@@ -0,0 +1,485 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg17"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
sodipodi:docname="bg-spookycomp.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview19"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="0.64052329"
inkscape:cx="656.49448"
inkscape:cy="528.47415"
inkscape:window-width="1680"
inkscape:window-height="1027"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs14">
<inkscape:path-effect
effect="powerstroke"
id="path-effect1922"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1918"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1912"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1908"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1904"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1900"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1896"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1892"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1888"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1884"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1880"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1763"
is_visible="true"
lpeversion="1"
offset_points="0,5.5691234"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="spiro"
id="path-effect1761"
is_visible="true"
lpeversion="1" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1757"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect1751"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect563"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="spiro"
id="path-effect561"
is_visible="true"
lpeversion="1" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect130"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
<inkscape:path-effect
effect="powerstroke"
id="path-effect126"
is_visible="true"
lpeversion="1"
offset_points="0,4.99214"
not_jump="false"
sort_points="true"
interpolator_type="CubicBezierJohan"
interpolator_beta="0.2"
start_linecap_type="zerowidth"
linejoin_type="extrp_arc"
miter_limit="4"
scale_width="1"
end_linecap_type="zerowidth" />
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
id="rect154"
width="3"
height="137.14046"
x="102.10482"
y="79.604454"
style="stroke-width:0.178258" />
<rect
id="rect154-2"
width="3"
height="137.14046"
x="145.10205"
y="36.723087"
style="stroke-width:0.178258"
transform="matrix(0,1,1,0,0,0)" />
<path
style="fill:#000000;fill-rule:nonzero;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 36.723085,145.10237 c 0,0 4.987117,0.2239 4.987117,0.2239 0.300118,-6.6849 1.730643,-14.5799 5.277526,-22.81733 2.867504,-6.65962 7.114921,-13.49712 13.016672,-19.54839 5.224311,-5.356666 11.731407,-10.067989 19.308093,-13.542282 6.97178,-3.196913 14.784137,-5.308406 22.979127,-5.811643 8.24259,-0.499 16.80948,0.649022 25.06489,3.495893 7.94206,2.738819 15.51771,7.028172 22.01161,12.780171 6.34679,5.621701 11.61373,12.603901 15.42154,20.432921 3.76329,7.73751 6.06614,16.23388 6.58031,24.89719 0.52517,8.91092 -0.85173,17.91943 -3.88779,26.34203 -3.07034,8.51768 -7.80955,16.36198 -13.9045,22.89384 -6.23852,6.68572 -13.82833,11.92776 -22.00751,15.53139 -8.49851,3.74432 -17.55572,5.69123 -26.46245,5.77934 -9.366947,0.0931 -18.471828,-1.86736 -26.615794,-5.25394 -8.853636,-3.68168 -16.507202,-9.00202 -22.592028,-15.25109 -6.874223,-7.05977 -11.65295,-15.18052 -14.685427,-23.08877 -3.738308,-9.74896 -4.835824,-19.17642 -4.491386,-27.06323 -0.344161,7.88048 0.651619,17.26919 4.281544,27.14203 2.929572,7.96799 7.589765,16.22578 14.389894,23.49234 6.021907,6.43495 13.659277,12.00387 22.585104,15.96109 8.207593,3.63879 17.462392,5.884 27.122323,6.03277 9.177,0.14093 18.59319,-1.61989 27.52011,-5.2724 8.58728,-3.51354 16.68109,-8.76935 23.43999,-15.62489 6.61021,-6.70474 11.85328,-14.84869 15.363,-23.79268 3.46859,-8.83914 5.22798,-18.42405 4.93218,-28.04869 -0.28403,-9.35938 -2.50148,-18.61389 -6.34083,-27.12228 -3.88289,-8.60485 -9.4086,-16.41368 -16.23918,-22.818104 -6.98566,-6.549834 -15.22822,-11.531792 -23.94415,-14.807737 -9.05708,-3.404166 -18.59294,-4.962432 -27.91504,-4.641543 -9.264368,0.311728 -18.145211,2.45759 -26.11948,5.87195 -8.665655,3.710393 -16.218184,8.890569 -22.365921,14.9262 -6.942635,6.816034 -11.969212,14.578794 -15.377784,22.176114 -4.203157,9.36837 -5.969196,18.51307 -6.318877,26.30193 0,0 4.987117,0.2239 4.987117,0.2239 z"
id="path559"
inkscape:path-effect="#path-effect561;#path-effect563"
inkscape:original-d="M 36.723085,145.10237 C 13.928908,121.22123 80.311166,101.43733 102.10482,79.604451 123.89852,57.771577 149.94429,123.27003 173.8636,145.10237 197.78291,166.93472 128.02471,192.86439 105.10483,216.745 82.184966,240.62561 59.517258,168.98351 36.723085,145.10237" />
<path
sodipodi:type="spiral"
style="fill:none;fill-rule:evenodd;stroke:#000000"
id="path588"
sodipodi:cx="352.83652"
sodipodi:cy="484.75989"
sodipodi:expansion="2"
sodipodi:revolution="2"
sodipodi:radius="260.29077"
sodipodi:argument="-12.56"
sodipodi:t0="0"
d="m 352.83652,484.75989 c 1.80546,0.0115 0.37587,3.56205 -0.0259,4.06696 -4.60433,5.78615 -13.30446,0.50913 -16.24194,-4.17059 -8.85183,-14.10194 3.27598,-30.98529 16.50102,-36.49902 27.92914,-11.6441 56.6858,10.82962 64.8382,37.01717 14.35477,46.11111 -22.14063,90.45747 -65.71906,101.2595 -68.68363,17.02499 -132.31907,-37.2052 -145.7629,-102.6067 -19.6647,-95.66475 56.02244,-182.27918 147.68006,-198.3484 127.06353,-22.27652 240.34225,78.59247 259.01602,200.93917"
transform="matrix(0.26458333,0,0,0.26458333,11.641668,16.404171)" />
<path
sodipodi:type="spiral"
style="fill:none;fill-rule:evenodd;stroke:#000000"
id="path592"
sodipodi:cx="357.52017"
sodipodi:cy="500.37213"
sodipodi:expansion="2"
sodipodi:revolution="2"
sodipodi:radius="262.7373"
sodipodi:argument="-15.698009"
sodipodi:t0="0"
d="m 357.52017,500.37213 c -1.82238,-0.0181 -0.36651,-3.59687 0.0409,-4.10507 4.66851,-5.82383 13.43126,-0.46577 16.3794,4.26854 8.88396,14.26641 -3.41885,31.26447 -16.78806,36.78213 -28.23361,11.65242 -57.17905,-11.13643 -65.31328,-37.59946 -14.32276,-46.59615 22.67589,-91.227 66.70273,-101.97281 69.39035,-16.93639 133.42729,38.03341 146.76075,104.09785 19.50327,96.63446 -57.20817,183.78858 -149.78485,199.6771 C 227.18013,723.54642 113.20237,621.32013 94.795886,497.7567"
transform="matrix(0.26458333,0,0,0.26458333,11.641668,16.404171)" />
<path
sodipodi:type="spiral"
style="fill:none;fill-rule:evenodd;stroke:#000000"
id="path606"
sodipodi:cx="341.12109"
sodipodi:cy="498.98618"
sodipodi:expansion="2"
sodipodi:revolution="2"
sodipodi:radius="260.12018"
sodipodi:argument="-14.134142"
sodipodi:t0="0"
d="m 341.12109,498.98618 c 0.005,-1.80431 3.55845,-0.38754 4.06436,0.0123 5.79772,4.58194 0.55327,13.29396 -4.11354,16.24514 -14.06302,8.89313 -30.97576,-3.17022 -36.53005,-16.36809 -11.72977,-27.87175 10.63296,-56.68453 36.77595,-64.91909 46.03264,-14.49943 90.47169,21.8236 101.41226,65.33712 17.24335,68.58131 -36.73826,132.35598 -102.05159,146.00956 C 245.1427,665.27461 158.33251,589.92705 141.96749,498.38373 119.28093,371.47866 219.70455,257.93761 341.90796,238.86719"
transform="matrix(0.26458333,0,0,0.26458333,11.641668,16.404171)" />
<path
sodipodi:type="spiral"
style="fill:none;fill-rule:evenodd;stroke:#000000"
id="path608"
sodipodi:cx="352.83652"
sodipodi:cy="484.75989"
sodipodi:expansion="2"
sodipodi:revolution="2"
sodipodi:radius="272.43375"
sodipodi:argument="-10.997079"
sodipodi:t0="0"
d="m 352.83652,484.75989 c 0.003,1.88973 -3.72502,0.42275 -4.25678,0.006 -6.09384,-4.77128 -0.64252,-13.9205 4.23116,-17.03349 14.68639,-9.38073 32.4568,3.17331 38.33657,16.96944 12.41713,29.1352 -10.86727,59.4177 -38.20848,68.16601 -48.14245,15.40403 -94.857,-22.42725 -106.52178,-67.94824 -18.38478,-71.74528 37.84908,-138.79432 106.18874,-153.40393 99.96248,-21.36993 191.23861,57.1318 208.81242,152.92997 24.36229,132.80352 -80.27546,252.19456 -208.17195,272.74728"
transform="matrix(0.26458333,0,0,0.26458333,11.641668,16.404171)" />
<circle
id="path794"
style="fill:#000000;stroke:#000000;stroke-width:0.264583"
cx="18.870451"
cy="108.5196"
r="0.081887342" />
<circle
id="path796"
style="fill:#000000;stroke:#000000;stroke-width:0.264583"
cx="18.870451"
cy="108.5196"
r="0.081887342" />
<path
d="m 126.98522,143.28195 c -3.27046,-6.48597 -9.0726,-11.20854 -15.58618,-12.68617 -1.04833,-0.23781 -2.50165,-0.37755 -3.97586,-0.38226 l -2.32355,-0.007 v -3.97007 -3.97006 l 1.08432,-0.30595 c 3.28224,-0.92611 8.80859,-1.13649 12.18982,-0.46404 6.30139,1.25321 11.70179,4.22244 16.57174,9.11142 3.0558,3.06774 4.90763,5.56042 6.70478,9.02505 1.03763,2.00039 2.2783,4.85524 2.2783,5.24248 0,0.0542 -3.62035,0.0985 -8.04522,0.0985 h -8.04523 z"
id="path1090"
style="stroke-width:0.206537" />
<path
d="m 105.09963,194.22753 v -7.70599 l 0.98105,-0.35654 c 5.90087,-2.14445 10.51031,-5.13325 14.76587,-9.57427 5.53017,-5.77118 8.5582,-12.57972 8.95199,-20.12862 0.10948,-2.09879 -0.0849,-4.29079 -0.66636,-7.51281 l -0.12112,-0.67125 h 7.95799 7.958 l 0.20854,0.98105 c 0.88261,4.15212 0.98738,10.15706 0.25133,14.40595 -3.1837,18.378 -18.54921,33.66783 -37.96374,37.77671 l -2.32355,0.49176 z"
id="path1129"
style="stroke-width:0.206537" />
<path
d="M 91.364899,202.36544 C 69.61843,200.30668 49.668833,184.56715 40.872983,162.52909 c -1.506908,-3.77556 -3.173098,-9.57853 -3.617444,-12.59874 -0.07521,-0.51118 -0.183132,-1.09348 -0.239836,-1.294 -0.09709,-0.34334 0.248558,-0.36139 5.931042,-0.30981 l 6.03414,0.0548 0.466937,2.06537 c 3.230189,14.28786 13.112493,27.0456 25.812694,33.32338 5.932442,2.93243 10.722001,4.12951 17.240337,4.30896 3.559582,0.098 7.107994,-0.17264 9.035987,-0.68919 l 0.46472,-0.1245 v 7.53207 7.53207 l -1.70394,0.13265 c -2.219964,0.17281 -6.5851,0.12556 -8.932721,-0.0967 z"
id="path1168"
style="stroke-width:0.206537" />
<path
d="m 66.173147,142.75319 c -0.997159,-6.22099 -0.475025,-12.91654 1.463921,-18.77248 4.753145,-14.35532 17.043908,-25.953793 32.387142,-30.562861 0.90038,-0.270473 1.71363,-0.491768 1.80721,-0.491768 0.0936,0 0.17014,2.637184 0.17014,5.86041 v 5.860429 l -1.8938,0.66131 c -2.369816,0.82754 -5.960876,2.61826 -8.123249,4.05074 -8.919232,5.9086 -14.762782,14.73955 -16.028456,24.22271 -0.295764,2.21604 -0.114628,7.66368 0.316974,9.53295 0.170486,0.73837 0.31324,1.45867 0.31723,1.60066 0.0056,0.19968 -1.133414,0.25817 -5.026986,0.25817 h -5.03424 z"
id="path1207"
style="stroke-width:0.206537" />
<path
d="m 94.876025,172.0129 c -3.193883,-0.38298 -6.95121,-1.53354 -9.947703,-3.04616 -3.752951,-1.89449 -8.588597,-5.91972 -11.331567,-9.43248 -2.34225,-2.9996 -4.622316,-7.0641 -5.668441,-10.10471 l -0.396171,-1.1515 h 5.120886 5.120888 l 0.743754,1.49739 c 1.29113,2.59943 2.84229,4.73193 5.091253,6.99937 3.204017,3.23034 6.208752,5.07168 10.279012,6.29912 1.597779,0.48183 2.189943,0.54973 4.963242,0.56911 l 3.149012,0.022 5.3e-4,4.06692 c 5.3e-4,2.2368 -0.0799,4.11674 -0.17847,4.17763 -0.35926,0.22204 -5.338682,0.29609 -6.946378,0.10331 z"
id="path1246"
style="stroke-width:0.206537" />
<path
d="m 105.09963,167.08284 v -4.1208 l 1.80681,-0.8467 c 4.5027,-2.11002 7.83507,-5.92949 8.93892,-10.24551 0.22401,-0.87586 0.40729,-2.04233 0.40729,-2.59213 v -0.99965 h 3.19739 3.19739 l 0.13591,0.54154 c 0.0748,0.29784 0.0754,1.40276 0.001,2.45536 -0.50991,7.25404 -5.15867,13.97547 -12.34661,17.85137 -1.44501,0.77918 -4.65575,2.07732 -5.1379,2.07732 -0.12306,0 -0.2006,-1.59273 -0.2006,-4.1208 z"
id="path1285"
style="stroke-width:0.206537" />
<path
d="m 114.93647,143.83701 c -0.71206,-1.36277 -2.77019,-3.34813 -4.175,-4.02739 -1.33121,-0.64368 -3.65904,-0.80428 -4.83536,-0.33362 l -0.82648,0.33069 v -2.34628 -2.34628 l 1.20114,-0.33703 c 1.51303,-0.42453 4.12627,-0.43309 5.71711,-0.0187 2.60244,0.67785 5.46662,2.69793 7.41207,5.22767 0.85072,1.10622 2.1764,3.5148 2.4893,4.52272 l 0.14427,0.46471 -3.26687,-5.3e-4 -3.26687,-5.3e-4 z"
id="path1324"
style="stroke-width:0.206537" />
<path
d="m 99.729642,158.90229 c -3.892311,-0.83899 -7.705918,-4.00523 -9.686893,-8.04253 -1.324816,-2.70002 -1.34443,-2.58264 0.430451,-2.57638 l 1.511311,0.005 0.399629,0.87245 c 0.53417,1.16618 2.65779,3.2561 3.937643,3.87516 1.334524,0.64551 3.591898,0.79923 4.733287,0.32233 0.43472,-0.18164 0.82552,-0.33025 0.86844,-0.33025 0.0429,0 0.0781,1.39413 0.0781,3.09805 0,3.56443 0.20794,3.31037 -2.271915,2.77584 z"
id="path1402"
style="stroke-width:0.206537" />
<path
d="m 105.09963,153.44147 c 0,-4.27576 0.0495,-5.16342 0.28771,-5.16342 0.15824,0 0.3412,0.13941 0.40659,0.30981 0.0654,0.17039 0.22469,0.3098 0.354,0.3098 0.12931,0 0.18162,-0.13941 0.11623,-0.3098 -0.10018,-0.26108 0.17013,-0.30981 1.71849,-0.30981 1.72581,0 1.86265,0.0321 2.25368,0.52925 0.65745,0.83581 0.91404,1.89207 0.80118,3.29809 -0.13393,1.6684 -0.90549,3.09586 -2.4425,4.51886 -1.04768,0.96996 -2.72477,1.98064 -3.28659,1.98064 -0.13513,0 -0.20879,-1.82172 -0.20879,-5.16342 z"
id="path1441"
style="stroke-width:0.206537" />
<path
d="m 100.75989,144.30222 c -1.054579,-1.72892 -0.70644,-4.40733 0.82551,-6.35101 l 0.40697,-0.51634 0.005,3.7693 c 0.004,3.64229 -0.009,3.76929 -0.41152,3.76929 -0.24778,0 -0.58175,-0.27154 -0.82555,-0.67124 z"
id="path1480"
style="stroke-width:0.206537" />
<path
d="m 88.26762,144.09568 c -0.15404,-1.05799 0.158348,-3.94911 0.62217,-5.75813 0.45044,-1.75681 1.932824,-4.85906 3.130714,-6.55178 1.958669,-2.76776 5.02625,-5.55611 8.018946,-7.28898 2.15262,-1.24645 1.96211,-1.51114 1.96211,2.7261 v 3.71629 l -0.56798,0.21496 c -5.747699,2.17536 -10.171948,7.61842 -10.171948,12.51432 v 1.305 h -1.433105 -1.433103 z"
id="path1519"
style="stroke-width:0.206537" />
<path
d="m 160.24563,143.78587 c -1.51564,-7.65278 -5.46257,-16.10019 -10.4788,-22.42723 -1.78023,-2.24542 -5.69501,-6.17985 -8.00687,-8.04706 -6.75285,-5.45404 -14.62519,-8.91514 -22.69533,-9.9781 -3.79729,-0.50016 -10.13597,-0.29111 -13.50029,0.44523 l -0.46471,0.10172 v -5.863461 -5.863437 l 2.73663,-0.377465 c 3.939,-0.543314 10.40728,-0.503782 14.30269,0.08741 12.26895,1.862013 22.88438,7.200529 32.28156,16.234483 4.98515,4.79246 10.20152,11.80312 12.03724,16.1777 2.35023,5.60068 4.22731,13.20464 4.65359,18.85135 l 0.13939,1.84645 h -5.38496 -5.38494 z"
id="path1597"
style="stroke-width:0.206537" />
<path
d="m 116.50215,214.06738 c 22.1136,-7.64458 39.08223,-26.21473 43.60949,-47.72541 1.04027,-4.94274 1.45696,-11.91282 0.99038,-16.56653 l -0.15013,-1.49739 h 5.22306 5.22304 v 1.64105 c 0,4.29954 -0.90775,10.86004 -2.15894,15.60308 -2.59664,9.84335 -6.99351,18.46458 -13.32573,26.12861 -2.11449,2.55921 -6.78651,7.13116 -9.43791,9.23575 -8.38779,6.65794 -18.37421,11.29037 -29.0579,13.47916 -2.91589,0.59739 -3.21983,0.49833 -0.91536,-0.29832 z"
id="path1636"
style="stroke-width:0.206537" />
<path
d="m 41.899323,143.95972 c 0,-0.55755 0.145259,-2.16079 0.322799,-3.56276 1.686547,-13.31801 7.231973,-25.50748 16.199033,-35.60731 2.081188,-2.3441 5.947534,-5.985995 6.145127,-5.788402 0.06484,0.06484 -0.390556,0.652986 -1.011981,1.307002 -1.639054,1.725 -4.279542,5.09892 -5.813313,7.42802 -5.566373,8.45278 -8.676362,17.41684 -9.450139,27.23859 -0.223827,2.84107 -0.151334,7.24213 0.151934,9.22409 l 0.118513,0.77451 H 45.23031 41.899323 Z"
id="path1675"
style="stroke-width:0.206537" />
<path
style="fill:#000000;fill-rule:nonzero;stroke:none;stroke-width:0.295161px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 102.12955,243.43706 c 11.25016,0.25675 24.56683,-1.47659 38.43732,-6.95933 11.22611,-4.43747 22.73421,-11.32079 32.79313,-21.22654 8.91218,-8.77646 16.48815,-19.7812 21.70901,-32.49444 4.8011,-11.69111 7.58082,-24.79462 7.36636,-38.37962 -0.20039,-12.69348 -3.01847,-25.56865 -8.36268,-37.66606 -5.14172,-11.639035 -12.6125,-22.520013 -22.18992,-31.562188 -9.35875,-8.835721 -20.56359,-15.761534 -32.75484,-20.35898 -12.05141,-4.54471 -25.03567,-6.800272 -38.03582,-6.366265 -12.390252,0.413645 -24.608176,3.254989 -35.876407,8.138838 -11.398526,4.940321 -21.792147,11.95442 -30.456005,20.63879 -8.866289,8.88728 -15.774918,19.379381 -20.550805,30.533285 -4.9633192,11.59165 -7.6117573,23.8555 -7.8889733,35.95198 -0.3037451,13.25411 2.24251,26.0642 6.7367143,37.5524 4.886358,12.49063 12.04215,23.37835 20.50917,32.16857 9.556488,9.92126 20.554633,16.99368 31.347742,21.71619 13.332682,5.8337 26.238928,8.06286 37.216004,8.31337 z m 0.25414,-11.13534 c -9.683046,-0.22099 -21.138632,-2.18998 -33.005305,-7.38223 -9.586507,-4.19457 -19.358016,-10.48465 -27.790551,-19.23906 -7.462518,-7.74737 -13.813214,-17.392 -18.158427,-28.49935 -3.997641,-10.21887 -6.241669,-21.56662 -5.974164,-33.23936 0.244149,-10.65357 2.580154,-21.5175 6.992747,-31.82295 4.246624,-9.91782 10.376889,-19.212323 18.196944,-27.050892 7.642059,-7.660153 16.853954,-13.88822 27.000144,-18.285756 10.030766,-4.34751 20.875353,-6.861101 31.818672,-7.226441 11.47682,-0.38315 23.00173,1.608787 33.734,5.656038 10.85615,4.093966 20.78718,10.245831 29.03865,18.036154 8.44365,7.97176 15.07399,17.610287 19.64791,27.964027 4.75329,10.75978 7.23779,22.16638 7.4142,33.34104 0.18884,11.96195 -2.26106,23.57059 -6.53279,33.97263 -4.64379,11.30804 -11.36798,21.05606 -19.22099,28.7895 -8.87398,8.73885 -19.10071,14.8627 -29.07233,18.80429 -12.34777,4.88084 -24.16763,6.40877 -34.08871,6.18236 z"
id="path1759"
inkscape:path-effect="#path-effect1761;#path-effect1763"
inkscape:original-d="m 102.25662,237.86939 c 30.12282,31.35145 63.07392,-62.26928 94.61032,-93.40435 C 228.40341,113.32993 133.14131,84.148386 101.27793,53.989659 69.414652,23.830932 41.684656,113.87294 11.887581,143.81413 c -29.797083,29.94117 60.246343,62.7038 90.369039,94.05526 z" />
<path
style="fill:#000000;fill-rule:nonzero;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 165.5117,148.38132 c 0,0 -4.99214,0 -4.99214,0 0,10.77936 1.04633,31.42865 2.18094,52.91066 -23.01869,-21.05994 -45.3437,-41.53138 -56.46492,-52.49759 11.85522,11.68999 34.68939,35.95862 57.52356,60.22726 l 3.93286,4.17993 0.31577,-5.95726 c 1.24803,-23.5452 2.49607,-47.0904 2.49607,-58.863 0,0 -4.99214,0 -4.99214,0 z"
id="path1898"
inkscape:path-effect="#path-effect1900"
inkscape:original-d="m 165.5117,148.38132 v 58.863 l -59.27612,-58.44993" />
<path
style="fill:#000000;fill-rule:nonzero;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 165.61496,144.97346 c 0,0 4.99214,0 4.99214,0 0,-12.12373 -1.24803,-36.3712 -2.49607,-60.618659 l -0.30959,-6.01495 -3.95147,4.249963 c -23.36494,25.129956 -46.72989,50.259916 -58.85361,62.383646 11.38829,-11.3883 34.25273,-32.69541 57.81331,-54.604194 -1.13688,22.164154 -2.18685,43.484024 -2.18685,54.604194 0,0 4.99214,0 4.99214,0 z"
id="path1902"
inkscape:path-effect="#path-effect1904"
inkscape:original-d="M 165.61496,144.97346 V 84.354801 l -60.6186,60.618659" />
<circle
id="path1914"
style="fill:#000000;stroke:none;stroke-width:0.264583"
cx="40.96991"
cy="147.96793"
r="0.39687499" />
<path
style="fill:#000000;fill-rule:nonzero;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 43.241814,148.17478 c 0,0 -4.99214,0 -4.99214,0 0,11.95848 1.248035,35.87545 2.49607,59.79242 l 0.313977,6.01697 3.947081,-4.25198 c 22.848596,-24.61358 45.697193,-49.22716 57.562738,-61.0927 -11.129995,11.12999 -33.476504,31.92355 -56.518329,53.31616 1.135302,-21.83368 2.182743,-42.82549 2.182743,-53.78087 0,0 -4.99214,0 -4.99214,0 z"
id="path1916"
inkscape:path-effect="#path-effect1918"
inkscape:original-d="M 43.241814,148.17478 V 207.9672 L 102.56954,148.63949" />
<path
style="fill:#000000;fill-rule:nonzero;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 44.501487,145.28776 c 0,0 4.99214,0 4.99214,0 0,-6.45338 -0.644297,-17.54355 -1.46996,-29.93895 -0.570708,-9.0485 -1.228068,-18.755587 -1.8192,-27.959324 24.892194,23.784004 46.938157,44.981974 59.708393,57.752224 -13.237307,-13.23732 -35.530092,-36.4413 -60.371954,-62.450847 0,0 -2.294454,-2.402693 -2.294454,-2.402693 0,0 -0.214925,3.442111 -0.214925,3.442111 -0.646956,10.257402 -1.405264,21.361129 -2.05222,31.618529 -0.825663,12.3954 -1.46996,23.48557 -1.46996,29.93895 0,0 4.99214,0 4.99214,0 z"
id="path1920"
inkscape:path-effect="#path-effect1922"
inkscape:original-d="M 44.501487,145.28776 V 115.34881 83.730281 l 61.411373,61.411429" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 28 KiB

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="210mm" height="297mm" version="1.1" viewBox="0 0 210 297" xmlns="http://www.w3.org/2000/svg">
<rect x="102.1" y="79.604" width="3" height="137.14" stroke-width=".17826"/>
<rect transform="matrix(0,1,1,0,0,0)" x="145.1" y="36.723" width="3" height="137.14" stroke-width=".17826"/>
<path d="m36.723 145.1 4.9871 0.2239c0.30012-6.6849 1.7306-14.58 5.2775-22.817 2.8675-6.6596 7.1149-13.497 13.017-19.548 5.2243-5.3567 11.731-10.068 19.308-13.542 6.9718-3.1969 14.784-5.3084 22.979-5.8116 8.2426-0.499 16.809 0.64902 25.065 3.4959 7.9421 2.7388 15.518 7.0282 22.012 12.78 6.3468 5.6217 11.614 12.604 15.422 20.433 3.7633 7.7375 6.0661 16.234 6.5803 24.897 0.52517 8.9109-0.85173 17.919-3.8878 26.342-3.0703 8.5177-7.8096 16.362-13.904 22.894-6.2385 6.6857-13.828 11.928-22.008 15.531-8.4985 3.7443-17.556 5.6912-26.462 5.7793-9.3669 0.0931-18.472-1.8674-26.616-5.2539-8.8536-3.6817-16.507-9.002-22.592-15.251-6.8742-7.0598-11.653-15.181-14.685-23.089-3.7383-9.749-4.8358-19.176-4.4914-27.063-0.34416 7.8805 0.65162 17.269 4.2815 27.142 2.9296 7.968 7.5898 16.226 14.39 23.492 6.0219 6.435 13.659 12.004 22.585 15.961 8.2076 3.6388 17.462 5.884 27.122 6.0328 9.177 0.14093 18.593-1.6199 27.52-5.2724 8.5873-3.5135 16.681-8.7694 23.44-15.625 6.6102-6.7047 11.853-14.849 15.363-23.793 3.4686-8.8391 5.228-18.424 4.9322-28.049-0.28403-9.3594-2.5015-18.614-6.3408-27.122-3.8829-8.6048-9.4086-16.414-16.239-22.818-6.9857-6.5498-15.228-11.532-23.944-14.808-9.0571-3.4042-18.593-4.9624-27.915-4.6415-9.2644 0.31173-18.145 2.4576-26.119 5.872-8.6657 3.7104-16.218 8.8906-22.366 14.926-6.9426 6.816-11.969 14.579-15.378 22.176-4.2032 9.3684-5.9692 18.513-6.3189 26.302l4.9871 0.2239z"/>
<path transform="matrix(.26458 0 0 .26458 11.642 16.404)" d="m352.84 484.76c1.8055 0.0115 0.37587 3.562-0.0259 4.067-4.6043 5.7862-13.304 0.50913-16.242-4.1706-8.8518-14.102 3.276-30.985 16.501-36.499 27.929-11.644 56.686 10.83 64.838 37.017 14.355 46.111-22.141 90.457-65.719 101.26-68.684 17.025-132.32-37.205-145.76-102.61-19.665-95.665 56.022-182.28 147.68-198.35 127.06-22.277 240.34 78.592 259.02 200.94" fill="none" stroke="#000"/>
<path transform="matrix(.26458 0 0 .26458 11.642 16.404)" d="m357.52 500.37c-1.8224-0.0181-0.36651-3.5969 0.0409-4.1051 4.6685-5.8238 13.431-0.46577 16.379 4.2685 8.884 14.266-3.4188 31.264-16.788 36.782-28.234 11.652-57.179-11.136-65.313-37.599-14.323-46.596 22.676-91.227 66.703-101.97 69.39-16.936 133.43 38.033 146.76 104.1 19.503 96.634-57.208 183.79-149.78 199.68-128.34 22.026-242.32-80.2-260.72-203.76" fill="none" stroke="#000"/>
<path transform="matrix(.26458 0 0 .26458 11.642 16.404)" d="m341.12 498.99c5e-3 -1.8043 3.5584-0.38754 4.0644 0.0123 5.7977 4.5819 0.55327 13.294-4.1135 16.245-14.063 8.8931-30.976-3.1702-36.53-16.368-11.73-27.872 10.633-56.685 36.776-64.919 46.033-14.499 90.472 21.824 101.41 65.337 17.243 68.581-36.738 132.36-102.05 146.01-95.536 19.971-182.35-55.376-198.71-146.92-22.687-126.91 77.737-240.45 199.94-259.52" fill="none" stroke="#000"/>
<path transform="matrix(.26458 0 0 .26458 11.642 16.404)" d="m352.84 484.76c3e-3 1.8897-3.725 0.42275-4.2568 6e-3 -6.0938-4.7713-0.64252-13.92 4.2312-17.033 14.686-9.3807 32.457 3.1733 38.337 16.969 12.417 29.135-10.867 59.418-38.208 68.166-48.142 15.404-94.857-22.427-106.52-67.948-18.385-71.745 37.849-138.79 106.19-153.4 99.962-21.37 191.24 57.132 208.81 152.93 24.362 132.8-80.275 252.19-208.17 272.75" fill="none" stroke="#000"/>
<circle cx="18.87" cy="108.52" r=".081887" stroke="#000" stroke-width=".26458"/>
<circle cx="18.87" cy="108.52" r=".081887" stroke="#000" stroke-width=".26458"/>
<path d="m126.99 143.28c-3.2705-6.486-9.0726-11.209-15.586-12.686-1.0483-0.23781-2.5016-0.37755-3.9759-0.38226l-2.3236-7e-3v-7.9401l1.0843-0.30595c3.2822-0.92611 8.8086-1.1365 12.19-0.46404 6.3014 1.2532 11.702 4.2224 16.572 9.1114 3.0558 3.0677 4.9076 5.5604 6.7048 9.025 1.0376 2.0004 2.2783 4.8552 2.2783 5.2425 0 0.0542-3.6204 0.0985-8.0452 0.0985h-8.0452z" stroke-width=".20654"/>
<path d="m105.1 194.23v-7.706l0.98105-0.35654c5.9009-2.1444 10.51-5.1332 14.766-9.5743 5.5302-5.7712 8.5582-12.58 8.952-20.129 0.10948-2.0988-0.0849-4.2908-0.66636-7.5128l-0.12112-0.67125h15.916l0.20854 0.98105c0.88261 4.1521 0.98738 10.157 0.25133 14.406-3.1837 18.378-18.549 33.668-37.964 37.777l-2.3236 0.49176z" stroke-width=".20654"/>
<path d="m91.365 202.37c-21.746-2.0588-41.696-17.798-50.492-39.836-1.5069-3.7756-3.1731-9.5785-3.6174-12.599-0.07521-0.51118-0.18313-1.0935-0.23984-1.294-0.09709-0.34334 0.24856-0.36139 5.931-0.30981l6.0341 0.0548 0.46694 2.0654c3.2302 14.288 13.112 27.046 25.813 33.323 5.9324 2.9324 10.722 4.1295 17.24 4.309 3.5596 0.098 7.108-0.17264 9.036-0.68919l0.46472-0.1245v15.064l-1.7039 0.13265c-2.22 0.17281-6.5851 0.12556-8.9327-0.0967z" stroke-width=".20654"/>
<path d="m66.173 142.75c-0.99716-6.221-0.47502-12.917 1.4639-18.772 4.7531-14.355 17.044-25.954 32.387-30.563 0.90038-0.27047 1.7136-0.49177 1.8072-0.49177 0.0936 0 0.17014 2.6372 0.17014 5.8604v5.8604l-1.8938 0.66131c-2.3698 0.82754-5.9609 2.6183-8.1232 4.0507-8.9192 5.9086-14.763 14.74-16.028 24.223-0.29576 2.216-0.11463 7.6637 0.31697 9.533 0.17049 0.73837 0.31324 1.4587 0.31723 1.6007 0.0056 0.19968-1.1334 0.25817-5.027 0.25817h-5.0342z" stroke-width=".20654"/>
<path d="m94.876 172.01c-3.1939-0.38298-6.9512-1.5335-9.9477-3.0462-3.753-1.8945-8.5886-5.9197-11.332-9.4325-2.3422-2.9996-4.6223-7.0641-5.6684-10.105l-0.39617-1.1515h10.242l0.74375 1.4974c1.2911 2.5994 2.8423 4.7319 5.0913 6.9994 3.204 3.2303 6.2088 5.0717 10.279 6.2991 1.5978 0.48183 2.1899 0.54973 4.9632 0.56911l3.149 0.022 5.3e-4 4.0669c5.3e-4 2.2368-0.0799 4.1167-0.17847 4.1776-0.35926 0.22204-5.3387 0.29609-6.9464 0.10331z" stroke-width=".20654"/>
<path d="m105.1 167.08v-4.1208l1.8068-0.8467c4.5027-2.11 7.8351-5.9295 8.9389-10.246 0.22401-0.87586 0.40729-2.0423 0.40729-2.5921v-0.99965h6.3948l0.13591 0.54154c0.0748 0.29784 0.0754 1.4028 1e-3 2.4554-0.50991 7.254-5.1587 13.975-12.347 17.851-1.445 0.77918-4.6558 2.0773-5.1379 2.0773-0.12306 0-0.2006-1.5927-0.2006-4.1208z" stroke-width=".20654"/>
<path d="m114.94 143.84c-0.71206-1.3628-2.7702-3.3481-4.175-4.0274-1.3312-0.64368-3.659-0.80428-4.8354-0.33362l-0.82648 0.33069v-4.6926l1.2011-0.33703c1.513-0.42453 4.1263-0.43309 5.7171-0.0187 2.6024 0.67785 5.4666 2.6979 7.4121 5.2277 0.85072 1.1062 2.1764 3.5148 2.4893 4.5227l0.14427 0.46471-6.5337-0.00106z" stroke-width=".20654"/>
<path d="m99.73 158.9c-3.8923-0.83899-7.7059-4.0052-9.6869-8.0425-1.3248-2.7-1.3444-2.5826 0.43045-2.5764l1.5113 5e-3 0.39963 0.87245c0.53417 1.1662 2.6578 3.2561 3.9376 3.8752 1.3345 0.64551 3.5919 0.79923 4.7333 0.32233 0.43472-0.18164 0.82552-0.33025 0.86844-0.33025 0.0429 0 0.0781 1.3941 0.0781 3.098 0 3.5644 0.20794 3.3104-2.2719 2.7758z" stroke-width=".20654"/>
<path d="m105.1 153.44c0-4.2758 0.0495-5.1634 0.28771-5.1634 0.15824 0 0.3412 0.13941 0.40659 0.30981 0.0654 0.17039 0.22469 0.3098 0.354 0.3098s0.18162-0.13941 0.11623-0.3098c-0.10018-0.26108 0.17013-0.30981 1.7185-0.30981 1.7258 0 1.8626 0.0321 2.2537 0.52925 0.65745 0.83581 0.91404 1.8921 0.80118 3.2981-0.13393 1.6684-0.90549 3.0959-2.4425 4.5189-1.0477 0.96996-2.7248 1.9806-3.2866 1.9806-0.13513 0-0.20879-1.8217-0.20879-5.1634z" stroke-width=".20654"/>
<path d="m100.76 144.3c-1.0546-1.7289-0.70644-4.4073 0.82551-6.351l0.40697-0.51634 5e-3 3.7693c4e-3 3.6423-9e-3 3.7693-0.41152 3.7693-0.24778 0-0.58175-0.27154-0.82555-0.67124z" stroke-width=".20654"/>
<path d="m88.268 144.1c-0.15404-1.058 0.15835-3.9491 0.62217-5.7581 0.45044-1.7568 1.9328-4.8591 3.1307-6.5518 1.9587-2.7678 5.0262-5.5561 8.0189-7.289 2.1526-1.2464 1.9621-1.5111 1.9621 2.7261v3.7163l-0.56798 0.21496c-5.7477 2.1754-10.172 7.6184-10.172 12.514v1.305h-2.8662z" stroke-width=".20654"/>
<path d="m160.25 143.79c-1.5156-7.6528-5.4626-16.1-10.479-22.427-1.7802-2.2454-5.695-6.1798-8.0069-8.0471-6.7528-5.454-14.625-8.9151-22.695-9.9781-3.7973-0.50016-10.136-0.29111-13.5 0.44523l-0.46471 0.10172v-11.727l2.7366-0.37746c3.939-0.54331 10.407-0.50378 14.303 0.08741 12.269 1.862 22.884 7.2005 32.282 16.234 4.9852 4.7925 10.202 11.803 12.037 16.178 2.3502 5.6007 4.2273 13.205 4.6536 18.851l0.13939 1.8464h-10.77z" stroke-width=".20654"/>
<path d="m116.5 214.07c22.114-7.6446 39.082-26.215 43.609-47.725 1.0403-4.9427 1.457-11.913 0.99038-16.567l-0.15013-1.4974h10.446v1.641c0 4.2995-0.90775 10.86-2.1589 15.603-2.5966 9.8434-6.9935 18.465-13.326 26.129-2.1145 2.5592-6.7865 7.1312-9.4379 9.2358-8.3878 6.6579-18.374 11.29-29.058 13.479-2.9159 0.59739-3.2198 0.49833-0.91536-0.29832z" stroke-width=".20654"/>
<path d="m41.899 143.96c0-0.55755 0.14526-2.1608 0.3228-3.5628 1.6865-13.318 7.232-25.507 16.199-35.607 2.0812-2.3441 5.9475-5.986 6.1451-5.7884 0.06484 0.06484-0.39056 0.65299-1.012 1.307-1.6391 1.725-4.2795 5.0989-5.8133 7.428-5.5664 8.4528-8.6764 17.417-9.4501 27.239-0.22383 2.8411-0.15133 7.2421 0.15193 9.2241l0.11851 0.77451h-6.662z" stroke-width=".20654"/>
<path d="m102.13 243.44c11.25 0.25675 24.567-1.4766 38.437-6.9593 11.226-4.4375 22.734-11.321 32.793-21.227 8.9122-8.7765 16.488-19.781 21.709-32.494 4.8011-11.691 7.5808-24.795 7.3664-38.38-0.20039-12.693-3.0185-25.569-8.3627-37.666-5.1417-11.639-12.612-22.52-22.19-31.562-9.3588-8.8357-20.564-15.762-32.755-20.359-12.051-4.5447-25.036-6.8003-38.036-6.3663-12.39 0.41364-24.608 3.255-35.876 8.1388-11.399 4.9403-21.792 11.954-30.456 20.639-8.8663 8.8873-15.775 19.379-20.551 30.533-4.9633 11.592-7.6118 23.856-7.889 35.952-0.30375 13.254 2.2425 26.064 6.7367 37.552 4.8864 12.491 12.042 23.378 20.509 32.169 9.5565 9.9213 20.555 16.994 31.348 21.716 13.333 5.8337 26.239 8.0629 37.216 8.3134zm0.25414-11.135c-9.683-0.22099-21.139-2.19-33.005-7.3822-9.5865-4.1946-19.358-10.485-27.791-19.239-7.4625-7.7474-13.813-17.392-18.158-28.499-3.9976-10.219-6.2417-21.567-5.9742-33.239 0.24415-10.654 2.5802-21.518 6.9927-31.823 4.2466-9.9178 10.377-19.212 18.197-27.051 7.6421-7.6602 16.854-13.888 27-18.286 10.031-4.3475 20.875-6.8611 31.819-7.2264 11.477-0.38315 23.002 1.6088 33.734 5.656 10.856 4.094 20.787 10.246 29.039 18.036 8.4436 7.9718 15.074 17.61 19.648 27.964 4.7533 10.76 7.2378 22.166 7.4142 33.341 0.18884 11.962-2.2611 23.571-6.5328 33.973-4.6438 11.308-11.368 21.056-19.221 28.79-8.874 8.7388-19.101 14.863-29.072 18.804-12.348 4.8808-24.168 6.4088-34.089 6.1824z"/>
<path d="m165.51 148.38h-4.9921c0 10.779 1.0463 31.429 2.1809 52.911-23.019-21.06-45.344-41.531-56.465-52.498 11.855 11.69 34.689 35.959 57.524 60.227l3.9329 4.1799 0.31577-5.9573c1.248-23.545 2.4961-47.09 2.4961-58.863h-4.9921z"/>
<path d="m165.61 144.97h4.9921c0-12.124-1.248-36.371-2.4961-60.619l-0.30959-6.015-3.9515 4.25c-23.365 25.13-46.73 50.26-58.854 62.384 11.388-11.388 34.253-32.695 57.813-54.604-1.1369 22.164-2.1868 43.484-2.1868 54.604h4.9921z"/>
<circle cx="40.97" cy="147.97" r=".39687"/>
<path d="m43.242 148.17h-4.9921c0 11.958 1.248 35.875 2.4961 59.792l0.31398 6.017 3.9471-4.252c22.849-24.614 45.697-49.227 57.563-61.093-11.13 11.13-33.477 31.924-56.518 53.316 1.1353-21.834 2.1827-42.825 2.1827-53.781h-4.9921z"/>
<path d="m44.501 145.29h4.9921c0-6.4534-0.6443-17.544-1.47-29.939-0.57071-9.0485-1.2281-18.756-1.8192-27.959 24.892 23.784 46.938 44.982 59.708 57.752-13.237-13.237-35.53-36.441-60.372-62.451l-2.2945-2.4027s-0.21492 3.4421-0.21492 3.4421c-0.64696 10.257-1.4053 21.361-2.0522 31.619-0.82566 12.395-1.47 23.486-1.47 29.939h4.9921z"/>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<svg id="em4uO9hb2pv1" viewBox="86.2 82.558 400 450" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" width="350px" height="400" xmlns="http://www.w3.org/2000/svg">
<style>
#em4uO9hb2pv4_to {animation: em4uO9hb2pv4_to__to 1000ms linear infinite normal forwards}@keyframes em4uO9hb2pv4_to__to { 0% {transform: translate(263.949556px,388px)} 100% {transform: translate(263.949556px,395.410979px)}} #em4uO9hb2pv5_to {animation: em4uO9hb2pv5_to__to 1000ms linear infinite normal forwards}@keyframes em4uO9hb2pv5_to__to { 0% {transform: translate(263.949556px,437.451142px)} 100% {transform: translate(263.949556px,477.856037px)}} #em4uO9hb2pv6_to {animation: em4uO9hb2pv6_to__to 1000ms linear infinite normal forwards}@keyframes em4uO9hb2pv6_to__to { 0% {transform: translate(263.949556px,477.451141px)} 100% {transform: translate(263.949556px,507px)}} #em4uO9hb2pv7_to {animation: em4uO9hb2pv7_to__to 1000ms linear infinite normal forwards}@keyframes em4uO9hb2pv7_to__to { 0% {transform: translate(257.595104px,408px)} 100% {transform: translate(257.595104px,437.856038px)}} #em4uO9hb2pv8_to {animation: em4uO9hb2pv8_to__to 1000ms linear infinite normal forwards}@keyframes em4uO9hb2pv8_to__to { 0% {transform: translate(258px,395.410979px)} 100% {transform: translate(258px,408px)}}
</style>
<defs>
<linearGradient id="em4uO9hb2pv2-fill" x1="257.848986" y1="84.30193" x2="256.478025" y2="378.040783" spreadMethod="pad" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1, 0, 0, 1, 32.317979, 15.69849)">
<stop id="em4uO9hb2pv2-fill-0" offset="0" stop-color="#e72696"/>
<stop id="em4uO9hb2pv2-fill-1" offset="1" stop-color="#facf31"/>
</linearGradient>
</defs>
<path d="M 449.76 259.593 C 449.76 260.889 449.745 262.181 449.714 263.47 L 130.62 263.47 C 130.589 262.181 130.574 260.889 130.574 259.593 C 130.574 257.386 130.619 255.189 130.708 253.003 L 449.626 253.003 C 449.715 255.189 449.76 257.386 449.76 259.593 Z M 434.441 327.907 L 145.893 327.907 C 143.917 323.74 142.115 319.473 140.498 315.117 L 439.836 315.117 C 438.219 319.473 436.417 323.74 434.441 327.907 Z M 133.453 289.922 L 446.881 289.922 C 446.151 293.719 445.286 297.468 444.291 301.164 L 136.043 301.164 C 135.048 297.468 134.183 293.719 133.453 289.922 Z M 131.064 272.19 L 449.27 272.19 C 449.095 274.432 448.873 276.661 448.607 278.876 L 131.727 278.876 C 131.461 276.661 131.239 274.432 131.064 272.19 Z M 290.167 100 C 373.937 100 442.632 164.541 449.239 246.609 L 131.095 246.609 C 137.702 164.541 206.397 100 290.167 100 Z M 414.785 359.303 L 165.549 359.303 C 161.689 354.485 158.102 349.438 154.813 344.186 L 425.521 344.186 C 422.232 349.438 418.645 354.485 414.785 359.303 Z M 375.047 394.767 L 205.287 394.767 C 197.384 389.794 189.949 384.148 183.06 377.908 L 397.274 377.908 C 390.385 384.148 382.95 389.794 375.047 394.767 Z" fill="url(#em4uO9hb2pv2-fill)"/>
<line x1="86.2" y1="414.95" x2="486.2" y2="414.039" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
<line x1="309.179" y1="473.781" x2="430.178" y2="473.506" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0.173648, 0.984808, -0.984808, 0.173648, 771.932387, 27.334005)">
<title>vert line 7</title>
</line>
<line x1="151.183" y1="475.044" x2="269.858" y2="474.604" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(-0.173648, 0.984808, -0.984808, -0.173648, 714.68734, 349.954016)">
<title>vert line 3</title>
</line>
<line x1="270.444" y1="473.493" x2="388.993" y2="473.225" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0.087156, 0.996195, -0.996195, 0.087156, 772.539295, 103.639124)">
<title>vert line 6</title>
</line>
<line x1="109.269" y1="473.663" x2="231.239" y2="473.385" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(-0.258819, 0.965926, -0.965926, -0.258819, 671.708034, 431.628247)">
<title>vert line 2</title>
</line>
<line x1="65.708" y1="473.725" x2="192.541" y2="473.436" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(-0.34202, 0.939693, -0.939693, -0.34202, 618.307795, 514.217141)">
<title>vert line 1</title>
</line>
<line x1="230.594" y1="473.242" x2="349.497" y2="472.971" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0, 1, -1, 0, 763.152008, 183.061005)">
<title>vert line 5</title>
</line>
<line x1="344.963" y1="473.597" x2="468.706" y2="473.315" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0.258819, 0.965926, -0.965926, 0.258819, 758.861416, -42.055348)">
<title>vert line 8</title>
</line>
<line x1="381.132" y1="473.023" x2="507.578" y2="473.402" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0.34202, 0.939693, -0.939693, 0.34202, 737.051091, -106.192735)">
<title>vert line 9</title>
</line>
<line x1="191.046" y1="473.586" x2="309.687" y2="473.316" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(-0.087156, 0.996195, -0.996195, -0.087156, 743.836818, 265.301309)">
<title>vert line 4</title>
</line>
<path d="" fill="none" stroke="#3f5787" stroke-width="0.8"/>
<line x1="86.2" y1="424.911" x2="486.2" y2="424" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
<line x1="86.2" y1="440.911" x2="486.2" y2="440" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
<line x1="86.2" y1="464.91" x2="486.2" y2="464" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
<line x1="86.2" y1="498.552" x2="486.2" y2="497.64" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
<line x1="422.842" y1="456.21" x2="516.415" y2="455.998" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0.422618, 0.906308, -0.906308, 0.422618, 684.525663, -162.281795)"/>
<line x1="60.198" y1="450.808" x2="141.309" y2="450.623" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(-0.422618, 0.906308, -0.906308, -0.422618, 551.820776, 549.882271)"/>
<line x1="83.53" y1="533.614" x2="489.497" y2="532.688" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<svg id="em4uO9hb2pv1" viewBox="86.2 82.558 400 450" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" width="350px" height="400" xmlns="http://www.w3.org/2000/svg">
<style>
#em4uO9hb2pv4_to {animation: em4uO9hb2pv4_to__to 1000ms linear infinite normal forwards}@keyframes em4uO9hb2pv4_to__to { 0% {transform: translate(263.949556px,388px)} 100% {transform: translate(263.949556px,395.410979px)}} #em4uO9hb2pv5_to {animation: em4uO9hb2pv5_to__to 1000ms linear infinite normal forwards}@keyframes em4uO9hb2pv5_to__to { 0% {transform: translate(263.949556px,437.451142px)} 100% {transform: translate(263.949556px,477.856037px)}} #em4uO9hb2pv6_to {animation: em4uO9hb2pv6_to__to 1000ms linear infinite normal forwards}@keyframes em4uO9hb2pv6_to__to { 0% {transform: translate(263.949556px,477.451141px)} 100% {transform: translate(263.949556px,507px)}} #em4uO9hb2pv7_to {animation: em4uO9hb2pv7_to__to 1000ms linear infinite normal forwards}@keyframes em4uO9hb2pv7_to__to { 0% {transform: translate(257.595104px,408px)} 100% {transform: translate(257.595104px,437.856038px)}} #em4uO9hb2pv8_to {animation: em4uO9hb2pv8_to__to 1000ms linear infinite normal forwards}@keyframes em4uO9hb2pv8_to__to { 0% {transform: translate(258px,395.410979px)} 100% {transform: translate(258px,408px)}}
</style>
<defs>
<linearGradient id="em4uO9hb2pv2-fill" x1="257.848986" y1="84.30193" x2="256.478025" y2="378.040783" spreadMethod="pad" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1, 0, 0, 1, 28.351456, -1.743511)">
<stop id="em4uO9hb2pv2-fill-0" offset="0" stop-color="#e72696"/>
<stop id="em4uO9hb2pv2-fill-1" offset="1" stop-color="#facf31"/>
</linearGradient>
</defs>
<path d="M 445.793 242.151 C 445.793 243.447 445.778 244.739 445.747 246.028 L 126.653 246.028 C 126.622 244.739 126.607 243.447 126.607 242.151 C 126.607 239.944 126.652 237.747 126.741 235.561 L 445.659 235.561 C 445.748 237.747 445.793 239.944 445.793 242.151 Z M 430.474 310.465 L 141.926 310.465 C 139.95 306.298 138.148 302.031 136.531 297.675 L 435.869 297.675 C 434.252 302.031 432.45 306.298 430.474 310.465 Z M 129.486 272.48 L 442.914 272.48 C 442.184 276.277 441.319 280.026 440.324 283.722 L 132.076 283.722 C 131.081 280.026 130.216 276.277 129.486 272.48 Z M 127.097 254.748 L 445.303 254.748 C 445.128 256.99 444.906 259.219 444.64 261.434 L 127.76 261.434 C 127.494 259.219 127.272 256.99 127.097 254.748 Z M 286.2 82.558 C 369.97 82.558 438.665 147.099 445.272 229.167 L 127.128 229.167 C 133.735 147.099 202.43 82.558 286.2 82.558 Z M 410.818 341.861 L 161.582 341.861 C 157.722 337.043 154.135 331.996 150.846 326.744 L 421.554 326.744 C 418.265 331.996 414.678 337.043 410.818 341.861 Z M 371.08 377.325 L 201.32 377.325 C 193.417 372.352 185.982 366.706 179.093 360.466 L 393.307 360.466 C 386.418 366.706 378.983 372.352 371.08 377.325 Z" fill="url(#em4uO9hb2pv2-fill)"/>
<line x1="86.2" y1="414.95" x2="486.2" y2="414.039" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
<line x1="309.179" y1="473.781" x2="430.178" y2="473.506" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0.173648, 0.984808, -0.984808, 0.173648, 771.932387, 27.334005)">
<title>vert line 7</title>
</line>
<line x1="151.183" y1="475.044" x2="269.858" y2="474.604" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(-0.173648, 0.984808, -0.984808, -0.173648, 714.68734, 349.954016)">
<title>vert line 3</title>
</line>
<line x1="270.444" y1="473.493" x2="388.993" y2="473.225" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0.087156, 0.996195, -0.996195, 0.087156, 772.539295, 103.639124)">
<title>vert line 6</title>
</line>
<line x1="109.269" y1="473.663" x2="231.239" y2="473.385" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(-0.258819, 0.965926, -0.965926, -0.258819, 671.708034, 431.628247)">
<title>vert line 2</title>
</line>
<line x1="65.708" y1="473.725" x2="192.541" y2="473.436" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(-0.34202, 0.939693, -0.939693, -0.34202, 618.307795, 514.217141)">
<title>vert line 1</title>
</line>
<line x1="230.594" y1="473.242" x2="349.497" y2="472.971" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0, 1, -1, 0, 763.152008, 183.061005)">
<title>vert line 5</title>
</line>
<line x1="344.963" y1="473.597" x2="468.706" y2="473.315" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0.258819, 0.965926, -0.965926, 0.258819, 758.861416, -42.055348)">
<title>vert line 8</title>
</line>
<line x1="381.132" y1="473.023" x2="507.578" y2="473.402" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0.34202, 0.939693, -0.939693, 0.34202, 737.051091, -106.192735)">
<title>vert line 9</title>
</line>
<line x1="191.046" y1="473.586" x2="309.687" y2="473.316" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(-0.087156, 0.996195, -0.996195, -0.087156, 743.836818, 265.301309)">
<title>vert line 4</title>
</line>
<path d="" fill="none" stroke="#3f5787" stroke-width="0.8"/>
<line x1="86.2" y1="424.911" x2="486.2" y2="424" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
<line x1="86.2" y1="440.911" x2="486.2" y2="440" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
<line x1="86.2" y1="464.91" x2="486.2" y2="464" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
<line x1="86.2" y1="498.552" x2="486.2" y2="497.64" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
<line x1="422.842" y1="456.21" x2="516.415" y2="455.998" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(0.422618, 0.906308, -0.906308, 0.422618, 684.525663, -162.281795)"/>
<line x1="60.198" y1="450.808" x2="141.309" y2="450.623" fill="none" stroke="#5edba5" stroke-width="3" style="" transform="matrix(-0.422618, 0.906308, -0.906308, -0.422618, 551.820776, 549.882271)"/>
<line x1="83.53" y1="533.614" x2="489.497" y2="532.688" fill="none" stroke="#5edba5" stroke-width="3" style=""/>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

+4 -2
View File
@@ -14,6 +14,7 @@
import { perf } from 'common/perf';
import { createAction } from 'common/redux';
import { globalEvents } from 'tgui-core/events';
import type { BooleanLike } from 'tgui-core/react';
import { setupDrag } from './drag';
import { focusMap } from './focus';
@@ -267,8 +268,9 @@ type BackendState<TData> = {
window: {
key: string;
size: [number, number];
fancy: boolean;
locked: boolean;
fancy: BooleanLike;
locked: BooleanLike;
scale: BooleanLike;
};
client: {
ckey: string;
@@ -56,7 +56,7 @@ export interface InteractiveProps {
}
export class Interactive extends Component<InteractiveProps> {
containerRef: RefObject<HTMLDivElement>;
containerRef: RefObject<HTMLDivElement | null>;
constructor(props: InteractiveProps) {
super(props);
+24 -10
View File
@@ -5,6 +5,7 @@
*/
import { storage } from 'common/storage';
import type { BooleanLike } from 'tgui-core/react';
import { vecAdd, vecMultiply, vecScale, vecSubtract } from 'tgui-core/vector';
import { createLogger } from './logging';
@@ -116,10 +117,11 @@ const storeWindowGeometry = async () => {
// Recall window geometry from local storage and apply it
export const recallWindowGeometry = async (
options: {
fancy?: boolean;
fancy?: BooleanLike;
pos?: [number, number];
size?: [number, number];
locked?: boolean;
locked?: BooleanLike;
scale?: BooleanLike;
} = {},
) => {
const geometry = options.fancy && (await storage.get(windowKey));
@@ -130,9 +132,21 @@ export const recallWindowGeometry = async (
let pos = geometry?.pos || options.pos;
let size = options.size;
// Convert size from css-pixels to display-pixels
if (size) {
if (options.scale && size) {
size = [size[0] * pixelRatio, size[1] * pixelRatio];
}
if (!options.scale) {
document.body.style.zoom = `${100 / window.devicePixelRatio}%`;
document.documentElement.style.setProperty(
'--scaling-amount',
window.devicePixelRatio.toString(),
);
} else {
document.body.style.zoom = '';
document.documentElement.style.setProperty('--scaling-amount', null);
}
// Wait until screen offset gets resolved
await screenOffsetPromise;
const areaAvailable = getScreenSize();
@@ -207,7 +221,7 @@ export const dragStartHandler = (event) => {
logger.log('drag start');
dragging = true;
dragPointOffset = vecSubtract(
[event.screenX, event.screenY],
[event.screenX * pixelRatio, event.screenY * pixelRatio],
getWindowPosition(),
) as [number, number];
// Focus click target
@@ -234,10 +248,10 @@ const dragMoveHandler = (event: MouseEvent) => {
}
event.preventDefault();
setWindowPosition(
vecSubtract([event.screenX, event.screenY], dragPointOffset) as [
number,
number,
],
vecSubtract(
[event.screenX * pixelRatio, event.screenY * pixelRatio],
dragPointOffset,
) as [number, number],
);
};
@@ -248,7 +262,7 @@ export const resizeStartHandler =
logger.log('resize start', resizeMatrix);
resizing = true;
dragPointOffset = vecSubtract(
[event.screenX, event.screenY],
[event.screenX * pixelRatio, event.screenY * pixelRatio],
getWindowPosition(),
) as [number, number];
initialSize = getWindowSize();
@@ -276,7 +290,7 @@ const resizeMoveHandler = (event: MouseEvent) => {
}
event.preventDefault();
const currentOffset = vecSubtract(
[event.screenX, event.screenY],
[event.screenX * pixelRatio, event.screenY * pixelRatio],
getWindowPosition(),
);
const delta = vecSubtract(currentOffset, dragPointOffset);
@@ -70,6 +70,7 @@ export const Canister = (props) => {
<LabeledControls.Item label="Regulator">
<Box position="relative" left="-8px">
<Knob
format={(value) => toFixed(value, 2)}
size={1.25}
color={!!valveOpen && 'yellow'}
value={releasePressure}
+1 -1
View File
@@ -16,7 +16,7 @@ type PaintCanvasProps = Partial<{
}>;
class PaintCanvas extends Component<PaintCanvasProps> {
canvasRef: RefObject<HTMLCanvasElement>;
canvasRef: RefObject<HTMLCanvasElement | null>;
mouseIsDown: boolean;
lastSuccessfulPaint: number;
onCVClick: (x: number, y: number) => void;
@@ -18,13 +18,13 @@ export const ChemDispenserChemicals = (props) => {
scrollable
buttons={<RecordingBlinker />}
>
<Stack direction="row" wrap="wrap" height="100%" align="flex-start">
<Stack direction="row" wrap="wrap" align="flex-start" g={0.3}>
{chemicals.map((c, i) => (
<Stack.Item key={i} grow m={0.2} basis="40%" height="20px">
<Stack.Item key={i} basis="40%" grow height="20px">
<Button
icon="arrow-circle-down"
width="100%"
height="100%"
fluid
ellipsis
align="flex-start"
onClick={() =>
act('dispense', {
@@ -7,6 +7,7 @@ import {
Section,
Stack,
} from 'tgui-core/components';
import { toFixed } from 'tgui-core/math';
import type { Data } from '../types';
@@ -27,6 +28,7 @@ export const DNAModifierMainRadiationEmitter = (props) => {
</Stack.Item>
<Stack.Item>
<Knob
format={(value) => toFixed(value)}
minValue={1}
maxValue={10}
stepPixelSize={20}
@@ -47,6 +49,7 @@ export const DNAModifierMainRadiationEmitter = (props) => {
</Stack.Item>
<Stack.Item>
<Knob
format={(value) => toFixed(value)}
minValue={1}
maxValue={20}
stepPixelSize={10}
@@ -1,6 +1,7 @@
import { useBackend } from 'tgui/backend';
import { Window } from 'tgui/layouts';
import { Button, Knob, LabeledList } from 'tgui-core/components';
import { toFixed } from 'tgui-core/math';
import type { Data } from './types';
@@ -53,6 +54,7 @@ export const Flamethrower = (props) => {
>
{!!constructed && (
<Knob
format={(value) => toFixed(value)}
size={1.5}
minValue={throw_min}
maxValue={throw_max}
@@ -55,6 +55,7 @@ export const GasTemperatureSystem = (props) => {
<LabeledControls>
<LabeledControls.Item label="Power Level">
<Knob
format={(value) => toFixed(value)}
minValue={0}
maxValue={100}
stepPixelSize={1}
@@ -1,6 +1,7 @@
import { useBackend } from 'tgui/backend';
import { Window } from 'tgui/layouts';
import { Button, Knob, Section, Table } from 'tgui-core/components';
import { toFixed } from 'tgui-core/math';
import type { BooleanLike } from 'tgui-core/react';
export const GyrotronControl = () => (
@@ -71,6 +72,7 @@ export const GyrotronControlContent = (props) => {
</Table.Cell>
<Table.Cell>
<Knob
format={(value) => toFixed(value)}
size={1.25}
color={!!gyro.active && 'yellow'}
value={gyro.fire_delay}
@@ -88,6 +90,7 @@ export const GyrotronControlContent = (props) => {
</Table.Cell>
<Table.Cell>
<Knob
format={(value) => toFixed(value)}
size={1.25}
color={!!gyro.active && 'yellow'}
value={gyro.strength}
@@ -28,7 +28,7 @@ export type PortProps = {
};
export type PortState = {
portRef: React.RefObject<HTMLSpanElement>;
portRef: React.RefObject<HTMLSpanElement | null>;
};
// eslint-disable-next-line react/prefer-stateless-function
@@ -21,11 +21,7 @@ export const JanitorCart = (props) => {
<Window width={225} height={180}>
<Window.Content>
<Stack wrap="wrap">
<Stack.Item
style={{
marginLeft: '0.5em', // Remove if tgui core implements gap
}}
>
<Stack.Item>
<Button
width="64px"
height="64px"
@@ -13,6 +13,7 @@ import {
Tabs,
TextArea,
} from 'tgui-core/components';
import { toFixed } from 'tgui-core/math';
import type { BooleanLike } from 'tgui-core/react';
type Data = {
@@ -208,6 +209,7 @@ const GeneralMobSettings = (props: {
</LabeledList.Item>
<LabeledList.Item label={'Size (' + props.sizeMultiplier + '%)'}>
<Knob
format={(value) => toFixed(value)}
value={props.sizeMultiplier}
minValue={50}
maxValue={200}
@@ -64,7 +64,7 @@ export const ModifyRobotModules = (props: {
<Stack vertical>
<Stack.Item>
<Button.Confirm
width="50px"
width="90px"
height="50px"
disabled={!source}
tooltip="Swaps the source and destination module types."
@@ -75,7 +75,7 @@ export const ModifyRobotModules = (props: {
</Stack.Item>
<Stack.Item>
<Button.Confirm
width="50px"
width="90px"
height="50px"
mt={40}
textAlign="center"
@@ -210,8 +210,8 @@ export const ModifyRobot = (props) => {
)}
</Stack>
</LabeledList.Item>
<LabeledList.Item label="AI Selection">
{!!target?.module && (
{!!target?.module && (
<LabeledList.Item label="AI Selection">
<Stack align="baseline">
<Stack.Item>
<Dropdown
@@ -247,8 +247,8 @@ export const ModifyRobot = (props) => {
</Button>
</Stack.Item>
</Stack>
)}
</LabeledList.Item>
</LabeledList.Item>
)}
</LabeledList>
<Divider />
{!!target &&
@@ -1,5 +1,6 @@
import { useBackend } from 'tgui/backend';
import { Button, Knob, LabeledList } from 'tgui-core/components';
import { toFixed } from 'tgui-core/math';
import type { Data } from './types';
@@ -34,7 +35,7 @@ export const OperatingComputerOptions = (props) => {
value={healthAlarm}
stepPixelSize={5}
ml="0"
format={(val) => val + '%'}
format={(val) => toFixed(val) + '%'}
onChange={(e, val: number) =>
act('health_adj', {
new: val,
@@ -59,7 +60,7 @@ export const OperatingComputerOptions = (props) => {
value={oxyAlarm}
stepPixelSize={5}
ml="0"
format={(val) => val + '%'}
format={(val) => toFixed(val) + '%'}
onChange={(e, val: number) =>
act('oxy_adj', {
new: val,
+2 -1
View File
@@ -1,3 +1,4 @@
import React from 'react';
import { useBackend } from 'tgui/backend';
import { Window } from 'tgui/layouts';
import {
@@ -49,7 +50,7 @@ export const PanDEMIC = () => {
resistances,
} = data;
let emptyPlaceholder: JSX.Element | null = null;
let emptyPlaceholder: React.JSX.Element | null = null;
if (!beakerLoaded) {
emptyPlaceholder = <>No container loaded.</>;
} else if (!beakerContainsBlood) {
+1 -1
View File
@@ -76,7 +76,7 @@ export const Pda = (props) => {
}
return (
<Window width={580} height={670} theme={useRetro ? 'pda-retro' : undefined}>
<Window width={580} height={670} theme={useRetro ? 'pda_retro' : undefined}>
<Window.Content scrollable>
<PDAHeader
settingsMode={settingsMode}
@@ -120,7 +120,7 @@ export const PowerMonitorFocus = (props: { focus: sensor }) => {
</Section>
</Stack.Item>
<Stack.Item mx={0.5} grow>
<Section position="relative" height="100%">
<Section position="relative" fill>
<Chart.Line
fillPositionedParent
data={supplyData}
@@ -13,10 +13,10 @@ type TabbedMenuProps = {
};
export class TabbedMenu extends Component<TabbedMenuProps> {
categoryRefs: Record<string, RefObject<HTMLDivElement>> = {};
sectionRef: RefObject<HTMLDivElement> = createRef();
categoryRefs: Record<string, RefObject<HTMLDivElement | null>> = {};
sectionRef: RefObject<HTMLDivElement | null> = createRef();
getCategoryRef(category: string): RefObject<HTMLDivElement> {
getCategoryRef(category: string): RefObject<HTMLDivElement | null> {
if (!this.categoryRefs[category]) {
this.categoryRefs[category] = createRef();
}
@@ -69,6 +69,13 @@ export const TGUI_SAY_LIGHT_MODE: FeatureToggle = {
component: CheckboxInput,
};
export const ui_scale: FeatureToggle = {
name: 'Toggle UI scaling',
category: 'UI',
description: 'If UIs should scale up to match your monitor scaling.',
component: CheckboxInput,
};
export const tgui_say_emotes: FeatureToggle = {
name: 'Say: Use TGUI For Emotes',
category: 'UI',
@@ -49,10 +49,9 @@ const UIStyleInput = (
return (
<Dropdown
selected={value}
clipSelectedText={false}
onSelected={props.handleSetValue}
width="100%"
menuWidth="20rem"
menuWidth={20}
options={sortChoices(Object.entries(choices)).map(
([dataValue, label]) => {
return {
@@ -50,15 +50,19 @@ export const WikiSearchPage = (
// Intentionally bad for the effect
useEffect(() => {
setNoData(false);
if (!search.length) {
setTimeout(() => {
if (!search.length && subCatActiveEntry && !noData) {
setNoData(true);
}
}, 200);
if (!search.length && !noData) {
setNoData(true);
} else if (search.length) {
setNoData(false);
}
}, [search || subCatActiveEntry]);
}, [search]);
function handleActiveEntry(neWEntry: string) {
if (activeEntry !== neWEntry) {
setActiveEntry(neWEntry);
setSubCatActiveEntry('');
}
}
const customSearch = createSearch(searchText, (search: string) => search);
const toDisplay = search.filter(customSearch);
@@ -142,7 +146,7 @@ export const WikiSearchPage = (
title={searchmode}
searchText={searchText}
onSearchText={setSearchText}
onActiveEntry={setActiveEntry}
onActiveEntry={handleActiveEntry}
listEntries={toDisplay}
activeEntry={activeEntry}
basis="30%"
@@ -1,30 +1,32 @@
import { Box, Section, Stack } from 'tgui-core/components';
import { Blink, Box, Section, Stack } from 'tgui-core/components';
import { WikiLogo } from '../../WikiCommon/WikiLogo';
export const WikiNoDataPage = (props) => {
return (
<Section fill scrollable>
<Stack vertical fill>
<Stack.Item>
<WikiLogo />
</Stack.Item>
<Stack.Item>
<Box textAlign="center" fontSize="32px">
Oh No... No Data...
</Box>
</Stack.Item>
<Stack.Item>
<Box textAlign="center" fontSize="24px">
We deeply sorry!!!
</Box>
</Stack.Item>
<Stack.Item>
<Box textAlign="center" color="label" fontSize="16px">
Maybe check back later!
</Box>
</Stack.Item>
</Stack>
<Blink>
<Stack vertical fill>
<Stack.Item>
<WikiLogo />
</Stack.Item>
<Stack.Item>
<Box textAlign="center" fontSize="32px">
Oh No... No Data...
</Box>
</Stack.Item>
<Stack.Item>
<Box textAlign="center" fontSize="24px">
We deeply sorry!!!
</Box>
</Stack.Item>
<Stack.Item>
<Box textAlign="center" color="label" fontSize="16px">
Maybe check back later!
</Box>
</Stack.Item>
</Stack>
</Blink>
</Section>
);
};
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { useBackend } from 'tgui/backend';
import { Window } from 'tgui/layouts';
import { Box, NoticeBox, Section, Stack } from 'tgui-core/components';
@@ -38,13 +38,14 @@ export const PublicLibraryWiki = (props) => {
donated,
goal,
} = data;
const tippOfTheDay = useRef(
WikiTippOfTheDay[Math.floor(Math.random() * WikiTippOfTheDay.length)],
);
const [displayedAds, setDisplayedAds] = useState<string[][]>([]);
const [displayDonation, setDislayDonation] = useState(false);
const [displayedDonations, setDisplayedDonations] = useState<string>('');
const [displayedDonated, setDisplayDonated] = useState<string>('');
const [tippOfTheDay, setTipOfTheDay] = useState<string>(
WikiTippOfTheDay[Math.floor(Math.random() * WikiTippOfTheDay.length)],
);
const [updateAds, setUpdateAds] = useState(false);
const [loadTime, setLoadTime] = useState(
Math.floor(Math.random() * 2000) + 2000,
@@ -127,7 +128,9 @@ export const PublicLibraryWiki = (props) => {
}, [has_donated]);
const tabs: React.JSX.Element[] = [];
tabs[0] = <WikiLoadingPage endTime={loadTime - 500} tipp={tippOfTheDay} />;
tabs[0] = (
<WikiLoadingPage endTime={loadTime - 500} tipp={tippOfTheDay.current} />
);
tabs[1] = crash ? (
<WikiErrorPage />
) : (
+1 -1
View File
@@ -4,7 +4,7 @@ import { RCONContent } from './RCONContent';
export const RCON = (props) => {
return (
<Window width={630} height={540}>
<Window width={630} height={580}>
<Window.Content scrollable>
<RCONContent />
</Window.Content>
@@ -105,40 +105,46 @@ const ConstructorPage = (props: {
return (
<Section title={our_name} fill>
<MaterialBars linked_data={linked_data} />
<Tabs>
<Tabs.Tab
selected={tab === ConstructorTabEnum.Build}
onClick={() => setTab(ConstructorTabEnum.Build)}
icon="wrench"
>
Build
</Tabs.Tab>
<Tabs.Tab
selected={tab === ConstructorTabEnum.Queue}
onClick={() => setTab(ConstructorTabEnum.Queue)}
color={queueColor}
icon={queueIcon}
iconSpin={queueSpin}
>
Queue
</Tabs.Tab>
<Tabs.Tab
selected={tab === ConstructorTabEnum.MatStorage}
onClick={() => setTab(ConstructorTabEnum.MatStorage)}
icon="cookie"
>
Mat Storage
</Tabs.Tab>
<Tabs.Tab
selected={tab === ConstructorTabEnum.ChemStorage}
onClick={() => setTab(ConstructorTabEnum.ChemStorage)}
icon="flask"
>
Chem Storage
</Tabs.Tab>
</Tabs>
{tabElement}
<Stack vertical fill>
<Stack.Item>
<MaterialBars linked_data={linked_data} />
</Stack.Item>
<Stack.Item>
<Tabs>
<Tabs.Tab
selected={tab === ConstructorTabEnum.Build}
onClick={() => setTab(ConstructorTabEnum.Build)}
icon="wrench"
>
Build
</Tabs.Tab>
<Tabs.Tab
selected={tab === ConstructorTabEnum.Queue}
onClick={() => setTab(ConstructorTabEnum.Queue)}
color={queueColor}
icon={queueIcon}
iconSpin={queueSpin}
>
Queue
</Tabs.Tab>
<Tabs.Tab
selected={tab === ConstructorTabEnum.MatStorage}
onClick={() => setTab(ConstructorTabEnum.MatStorage)}
icon="cookie"
>
Mat Storage
</Tabs.Tab>
<Tabs.Tab
selected={tab === ConstructorTabEnum.ChemStorage}
onClick={() => setTab(ConstructorTabEnum.ChemStorage)}
icon="flask"
>
Chem Storage
</Tabs.Tab>
</Tabs>
</Stack.Item>
<Stack.Item grow>{tabElement}</Stack.Item>
</Stack>
</Section>
);
};
@@ -184,9 +190,7 @@ const BuildTab = (props: {
<Section
title={`Designs (Page ${data.builder_page + 1})`}
fill
height="85%"
buttons={<PaginationChevrons target="builder_page" />}
scrollable
>
<Input
fluid
@@ -196,51 +200,54 @@ const BuildTab = (props: {
onInput={(e, v: string) => act('search', { search: v })}
mb={1}
/>
{designs?.length ? (
designs.map((design) => (
<Fragment key={design.id}>
<Stack justify="space-between" align="center">
<Stack.Item grow>{design.name}</Stack.Item>
<Stack.Item>
<Box inline color="label">
{design.mat_list.join(' ')}
</Box>
<Box inline color="average" ml={1}>
{design.chem_list.join(' ')}
</Box>
</Stack.Item>
<Stack.Item>
<Button
icon="wrench"
onClick={() =>
act(buildAct, { build: design.id, imprint: design.id })
}
>
Build
</Button>
{!!buildActFive && (
<Divider />
<Section fill scrollable>
{designs?.length ? (
designs.map((design) => (
<Fragment key={design.id}>
<Stack justify="space-between" align="center">
<Stack.Item grow>{design.name}</Stack.Item>
<Stack.Item>
<Box inline color="label">
{design.mat_list.join(' ')}
</Box>
<Box inline color="average" ml={1}>
{design.chem_list.join(' ')}
</Box>
</Stack.Item>
<Stack.Item>
<Button
icon="wrench"
onClick={() =>
act(buildActFive, {
build: design.id,
imprint: design.id,
})
act(buildAct, { build: design.id, imprint: design.id })
}
>
5
Build
</Button>
)}
</Stack.Item>
</Stack>
<Divider />
</Fragment>
))
) : (
<Box>
No items could be found matching the parameters (page or search).
</Box>
)}
{!!buildActFive && (
<Button
icon="wrench"
onClick={() =>
act(buildActFive, {
build: design.id,
imprint: design.id,
})
}
>
5
</Button>
)}
</Stack.Item>
</Stack>
<Divider />
</Fragment>
))
) : (
<Box>
No items could be found matching the parameters (page or search).
</Box>
)}
</Section>
</Section>
);
};
@@ -1,5 +1,12 @@
import { useBackend } from 'tgui/backend';
import { Box, Button, Input, LabeledList, Section } from 'tgui-core/components';
import {
Box,
Button,
Divider,
Input,
LabeledList,
Section,
} from 'tgui-core/components';
import { PaginationChevrons } from '..';
import type { Data } from '../data';
@@ -12,7 +19,6 @@ export const DesignList = (props) => {
title={`Design List (Page ${data.design_page + 1})`}
fill
textAlign="center"
scrollable
buttons={
<>
<Button icon="print" onClick={() => act('print', { print: 2 })}>
@@ -30,30 +36,33 @@ export const DesignList = (props) => {
onInput={(e, v) => act('search', { search: v })}
mb={1}
/>
{(!!data.designs?.length && (
<LabeledList>
{data.designs.map((design) => (
<LabeledList.Item
label={design.name}
key={design.id}
buttons={
!!(data.d_disk && !data.d_disk.stored) && (
<Button
icon="download"
onClick={() =>
act('copy_design', { copy_design_ID: design.id })
}
>
Save To Disk
</Button>
)
}
>
{design.desc}
</LabeledList.Item>
))}
</LabeledList>
)) || <Box color="warning">No designs found.</Box>}
<Divider />
<Section fill scrollable>
{(!!data.designs?.length && (
<LabeledList>
{data.designs.map((design) => (
<LabeledList.Item
label={design.name}
key={design.id}
buttons={
!!(data.d_disk && !data.d_disk.stored) && (
<Button
icon="download"
onClick={() =>
act('copy_design', { copy_design_ID: design.id })
}
>
Save To Disk
</Button>
)
}
>
{design.desc}
</LabeledList.Item>
))}
</LabeledList>
)) || <Box color="warning">No designs found.</Box>}
</Section>
</Section>
);
};
@@ -8,6 +8,7 @@ import {
LabeledList,
Section,
} from 'tgui-core/components';
import { toFixed } from 'tgui-core/math';
import type { BooleanLike } from 'tgui-core/react';
type Data = {
@@ -29,7 +30,7 @@ export const SpaceHeater = (props) => {
<Section title="Status">
<LabeledList>
<LabeledList.Item label="Target Temperature">
{temp} K ({temp - T0C}&deg; C)
{toFixed(temp, 2)} K ({toFixed(temp - T0C, 2)}&deg; C)
</LabeledList.Item>
<LabeledList.Item label="Current Charge">
{power}% {!cell && '(No Cell Inserted)'}
@@ -41,6 +42,7 @@ export const SpaceHeater = (props) => {
<LabeledControls.Item label="Thermostat">
<Knob
animated
format={(value) => toFixed(value, 2)}
value={temp - T0C}
minValue={minTemp - T0C}
maxValue={maxTemp - T0C}
@@ -1,5 +1,5 @@
import { useState } from 'react';
import { Section, Tabs } from 'tgui-core/components';
import { Section, Stack, Tabs } from 'tgui-core/components';
import { SupplyConsoleMenuHistoryExport } from './SupplyConsoleMenuHistoryExport';
import { SupplyConsoleMenuOrder } from './SupplyConsoleMenuOrder';
@@ -17,45 +17,49 @@ export const SupplyConsoleMenu = (props) => {
tab[4] = <SupplyConsoleMenuHistoryExport />;
return (
<Section title="Menu">
<Tabs>
<Tabs.Tab
icon="box"
selected={tabIndex === 0}
onClick={() => setTabIndex(0)}
>
Request
</Tabs.Tab>
<Tabs.Tab
icon="check-circle-o"
selected={tabIndex === 1}
onClick={() => setTabIndex(1)}
>
Accepted
</Tabs.Tab>
<Tabs.Tab
icon="circle-o"
selected={tabIndex === 2}
onClick={() => setTabIndex(2)}
>
Requests
</Tabs.Tab>
<Tabs.Tab
icon="book"
selected={tabIndex === 3}
onClick={() => setTabIndex(3)}
>
Order history
</Tabs.Tab>
<Tabs.Tab
icon="book"
selected={tabIndex === 4}
onClick={() => setTabIndex(4)}
>
Export history
</Tabs.Tab>
</Tabs>
{tab[tabIndex] || ''}
<Section fill title="Menu">
<Stack vertical fill>
<Stack.Item>
<Tabs>
<Tabs.Tab
icon="box"
selected={tabIndex === 0}
onClick={() => setTabIndex(0)}
>
Request
</Tabs.Tab>
<Tabs.Tab
icon="check-circle-o"
selected={tabIndex === 1}
onClick={() => setTabIndex(1)}
>
Accepted
</Tabs.Tab>
<Tabs.Tab
icon="circle-o"
selected={tabIndex === 2}
onClick={() => setTabIndex(2)}
>
Requests
</Tabs.Tab>
<Tabs.Tab
icon="book"
selected={tabIndex === 3}
onClick={() => setTabIndex(3)}
>
Order history
</Tabs.Tab>
<Tabs.Tab
icon="book"
selected={tabIndex === 4}
onClick={() => setTabIndex(4)}
>
Export history
</Tabs.Tab>
</Tabs>
</Stack.Item>
<Stack.Item grow>{tab[tabIndex] || ''}</Stack.Item>
</Stack>
</Section>
);
};
@@ -12,7 +12,7 @@ export const SupplyConsoleMenuHistoryExport = (props) => {
}
return (
<Section scrollable fill height="290px">
<Section scrollable fill>
{receipts.map((r, ri) => (
<Section key={ri}>
<LabeledList>
@@ -1,6 +1,14 @@
import { useState } from 'react';
import { useBackend } from 'tgui/backend';
import { Box, Button, Section, Stack } from 'tgui-core/components';
import {
Box,
Button,
Divider,
Input,
Section,
Stack,
} from 'tgui-core/components';
import { createSearch } from 'tgui-core/string';
import type { Data, supplyPack } from './types';
@@ -10,6 +18,8 @@ export const SupplyConsoleMenuOrder = (props) => {
const { categories, supply_packs, contraband, supply_points } = data;
const [activeCategory, setActiveCategory] = useState<string | null>(null);
const [searchCategory, setSearchCategory] = useState<string>('');
const [searchContent, setSearchContent] = useState<string>('');
function sortPack(a: supplyPack, b: supplyPack) {
if (a.cost < supply_points && b.cost > supply_points) return -1;
@@ -21,18 +31,32 @@ export const SupplyConsoleMenuOrder = (props) => {
const viewingPacks: supplyPack[] = supply_packs
.filter(
(pack) =>
(pack.group === activeCategory && !pack.contraband) || !!contraband,
pack.group === activeCategory && (!pack.contraband || !!contraband),
)
.sort((a, b) => sortPack(a, b));
// const viewingPacks = sortBy(val => val.name)(supply_packs).filter(val => val.group === activeCategory);
const categorySearch = createSearch(searchCategory);
const contentSearch = createSearch(
searchContent,
(pack: supplyPack) => pack.name,
);
const filteredCategories = categories.filter(categorySearch);
const filteredPack = viewingPacks.filter(contentSearch);
return (
<Section>
<Stack>
<Stack.Item basis="25%">
<Section title="Categories" scrollable fill height="290px">
{categories.map((category) => (
<Stack fill>
<Stack.Item basis="25%">
<Section title="Categories" fill>
<Input
fluid
placeholder={'Search for category...'}
value={searchCategory}
onInput={(e, val) => setSearchCategory(val)}
/>
<Divider />
<Section scrollable fill>
{filteredCategories.map((category) => (
<Button
key={category}
fluid
@@ -43,10 +67,19 @@ export const SupplyConsoleMenuOrder = (props) => {
</Button>
))}
</Section>
</Stack.Item>
<Stack.Item grow ml={2}>
<Section title="Contents" scrollable fill height="290px">
{viewingPacks.map((pack) => (
</Section>
</Stack.Item>
<Stack.Item grow ml={2}>
<Section title="Contents" fill>
<Input
fluid
placeholder={'Search for pack...'}
value={searchCategory}
onInput={(e, val) => setSearchContent(val)}
/>
<Divider />
<Section scrollable fill>
{filteredPack.map((pack) => (
<Box key={pack.name}>
<Stack align="center" justify="flex-start">
<Stack.Item maxWidth="70%" basis="70%">
@@ -101,8 +134,8 @@ export const SupplyConsoleMenuOrder = (props) => {
</Collapsible>
))} */}
</Section>
</Stack.Item>
</Stack>
</Section>
</Section>
</Stack.Item>
</Stack>
);
};
@@ -17,7 +17,7 @@ export const SupplyConsoleMenuOrderList = (props) => {
}
return (
<Section scrollable fill height="290px">
<Section scrollable fill>
{mode === 'Requested' && order_auth ? (
<Button
mt={-1}
@@ -55,7 +55,7 @@ export const SupplyConsoleShuttleStatus = (props) => {
}
return (
<Section>
<>
<LabeledList>
<LabeledList.Item label="Supply Points">
<AnimatedNumber value={supply_points} />
@@ -95,6 +95,6 @@ export const SupplyConsoleShuttleStatus = (props) => {
)}
</LabeledList>
</Section>
</Section>
</>
);
};
@@ -3,7 +3,7 @@ import {
modalRegisterBodyOverride,
} from 'tgui/interfaces/common/ComplexModal';
import { Window } from 'tgui/layouts';
import { Section } from 'tgui-core/components';
import { Section, Stack } from 'tgui-core/components';
import { SupplyConsoleMenu } from './SupplyConsoleMenu';
import { SupplyConsoleShuttleStatus } from './SupplyConsoleShuttleStatus';
@@ -14,11 +14,23 @@ export const SupplyConsole = (props) => {
return (
<Window width={700} height={620}>
<Window.Content>
<ComplexModal maxWidth="100%" />
<Section title="Supply Records">
<SupplyConsoleShuttleStatus />
<SupplyConsoleMenu />
</Section>
<Stack vertical fill>
<Stack.Item>
<ComplexModal maxWidth="100%" />
</Stack.Item>
<Stack.Item grow>
<Section fill title="Supply Records">
<Stack vertical fill>
<Stack.Item>
<SupplyConsoleShuttleStatus />
</Stack.Item>
<Stack.Item grow>
<SupplyConsoleMenu />
</Stack.Item>
</Stack>
</Section>
</Stack.Item>
</Stack>
</Window.Content>
</Window>
);
@@ -15,13 +15,7 @@ export const VoreUserPreferencesAesthetic = (props: {
return (
<Section title="Aesthetic Preferences">
<Stack wrap="wrap" justify="center">
<Stack.Item
basis="49%"
grow
style={{
marginLeft: '0.5em', // Remove if tgui core implements gap
}}
>
<Stack.Item basis="49%" grow>
<Button fluid icon="grin-tongue" onClick={() => act('setflavor')}>
Set Taste
</Button>
@@ -30,12 +30,7 @@ export const VoreUserPreferencesDevouring = (props: {
>
{devourable ? (
<Stack wrap="wrap" justify="center">
<Stack.Item
basis="32%"
style={{
marginLeft: '0.5em', // Remove if tgui core implements gap
}}
>
<Stack.Item basis="32%">
<VoreUserPreferenceItem
spec={preferences.healbelly}
tooltipPosition="right"
@@ -37,12 +37,7 @@ export const VoreUserPreferencesMechanical = (props: {
}
>
<Stack wrap="wrap" justify="center">
<Stack.Item
basis="32%"
style={{
marginLeft: '0.5em', // Remove if tgui core implements gap
}}
>
<Stack.Item basis="32%">
<VoreUserPreferenceItem
spec={preferences.steppref}
tooltipPosition="right"
@@ -24,12 +24,7 @@ export const VoreUserPreferencesSoulcatcher = (props: {
>
{soulcatcher_allow_capture ? (
<Stack wrap="wrap" justify="center">
<Stack.Item
basis="32%"
style={{
marginLeft: '0.5em', // Remove if tgui core implements gap
}}
>
<Stack.Item basis="32%">
<VoreUserPreferenceItem
spec={preferences.soulcatcher_transfer}
tooltipPosition="right"
@@ -44,12 +44,7 @@ export const VoreUserPreferencesSpawn = (props: {
<Stack wrap="wrap" justify="center">
{latejoin_vore ? (
<>
<Stack.Item
basis="31%"
style={{
marginLeft: '0.5em', // Remove if tgui core implements gap
}}
>
<Stack.Item basis="31%">
<VoreUserPreferenceItem
spec={preferences.no_spawnpred_warning}
tooltipPosition="top"
@@ -29,12 +29,7 @@ export const VoreUserPreferencesSpontaneous = (props: {
>
{can_be_drop_prey || can_be_drop_pred ? (
<Stack wrap="wrap" justify="center">
<Stack.Item
basis="32%"
style={{
marginLeft: '0.5em', // Remove if tgui core implements gap
}}
>
<Stack.Item basis="32%">
<VoreUserPreferenceItem
spec={preferences.toggle_drop_vore}
tooltipPosition="right"
+83
View File
@@ -0,0 +1,83 @@
import { type PropsWithChildren } from 'react';
import { Button, Icon } from 'tgui-core/components';
import { UI_DISABLED, UI_INTERACTIVE, UI_UPDATE } from 'tgui-core/constants';
import { type BooleanLike, classes } from 'tgui-core/react';
import { toTitleCase } from 'tgui-core/string';
import { globalStore } from '../backend';
import { toggleKitchenSink } from '../debug/actions';
type TitleBarProps = Partial<{
className: string;
title: string;
status: number;
fancy: BooleanLike;
canClose: BooleanLike;
onClose: (e) => void;
onDragStart: (e) => void;
}> &
PropsWithChildren;
function statusToColor(status: number): string {
switch (status) {
case UI_INTERACTIVE:
return 'good';
case UI_UPDATE:
return 'average';
case UI_DISABLED:
default:
return 'bad';
}
}
export function TitleBar(props: TitleBarProps) {
const {
className,
title,
status,
canClose,
fancy,
onDragStart,
onClose,
children,
} = props;
const dispatch = globalStore.dispatch;
const finalTitle =
(typeof title === 'string' &&
title === title.toLowerCase() &&
toTitleCase(title)) ||
title;
return (
<div className={classes(['TitleBar', className])}>
<div
className="TitleBar__dragZone"
onMouseDown={(e) => fancy && onDragStart && onDragStart(e)}
/>
{status === undefined ? (
<Icon className="TitleBar__statusIcon" name="tools" opacity={0.5} />
) : (
<Icon
className="TitleBar__statusIcon"
color={statusToColor(status)}
name={status === UI_DISABLED ? 'eye-slash' : 'eye'}
/>
)}
<div className="TitleBar__title">{finalTitle}</div>
{!!children && <div className="TitleBar__buttons">{children}</div>}
{process.env.NODE_ENV !== 'production' && (
<Button
className="TitleBar__buttons TitleBar__KitchenSink"
icon="bug"
onClick={() => dispatch(toggleKitchenSink())}
/>
)}
{Boolean(fancy && canClose) && (
<div className="TitleBar__close" onClick={onClose}>
<Icon className="TitleBar__close--icon" name="times" />
</div>
)}
</div>
);
}
+26 -87
View File
@@ -9,14 +9,15 @@ import {
type PropsWithChildren,
type ReactNode,
useEffect,
useLayoutEffect,
useState,
} from 'react';
import { backendSuspendStart, globalStore, useBackend } from 'tgui/backend';
import { UI_DISABLED, UI_INTERACTIVE, UI_UPDATE } from 'tgui/constants';
import { UI_DISABLED, UI_INTERACTIVE } from 'tgui/constants';
import { useDebug } from 'tgui/debug';
import { toggleKitchenSink } from 'tgui/debug/actions';
import { type Box, Icon } from 'tgui-core/components';
import { classes } from 'tgui-core/react';
import { decodeHtmlEntities, toTitleCase } from 'tgui-core/string';
import { type Box } from 'tgui-core/components';
import { type BooleanLike, classes } from 'tgui-core/react';
import { decodeHtmlEntities } from 'tgui-core/string';
import {
dragStartHandler,
@@ -26,14 +27,14 @@ import {
} from '../drag';
import { createLogger } from '../logging';
import { Layout } from './Layout';
import { TitleBar } from './TitleBar';
const logger = createLogger('Window');
const DEFAULT_SIZE: [number, number] = [400, 600];
type Props = Partial<{
buttons: ReactNode;
canClose: boolean;
canClose: BooleanLike;
height: number;
theme: string;
title: string;
@@ -54,9 +55,21 @@ export const Window = (props: Props) => {
const { config, suspended } = useBackend();
const { debugLayout = false } = useDebug();
const [isReadyToRender, setIsReadyToRender] = useState(false);
// We need to set the window to be invisible before we can set its geometry
// Otherwise, we get a flicker effect when the window is first rendered
useLayoutEffect(() => {
Byond.winset(Byond.windowId, {
'is-visible': false,
});
setIsReadyToRender(true);
}, []);
const { scale } = config.window;
useEffect(() => {
if (!suspended) {
if (!suspended && isReadyToRender) {
const updateGeometry = () => {
const options = {
...config.window,
@@ -70,6 +83,10 @@ export const Window = (props: Props) => {
setWindowKey(config.window.key);
}
recallWindowGeometry(options);
Byond.winset(Byond.windowId, {
'is-visible': true,
});
logger.log('set to visible');
};
Byond.winset(Byond.windowId, {
@@ -82,7 +99,7 @@ export const Window = (props: Props) => {
logger.log('unmounting');
};
}
}, [width, height]);
}, [isReadyToRender, width, height, scale]);
const dispatch = globalStore.dispatch;
const fancy = config.window?.fancy;
@@ -159,81 +176,3 @@ const WindowContent = (props: ContentProps) => {
};
Window.Content = WindowContent;
const statusToColor = (status) => {
switch (status) {
case UI_INTERACTIVE:
return 'good';
case UI_UPDATE:
return 'average';
case UI_DISABLED:
default:
return 'bad';
}
};
type TitleBarProps = Partial<{
canClose: boolean;
className: string;
fancy: boolean;
onClose: (e) => void;
onDragStart: (e) => void;
status: number;
title: string;
}> &
PropsWithChildren;
const TitleBar = (props: TitleBarProps) => {
const {
className,
title,
status,
canClose,
fancy,
onDragStart,
onClose,
children,
} = props;
const dispatch = globalStore.dispatch;
const finalTitle =
(typeof title === 'string' &&
title === title.toLowerCase() &&
toTitleCase(title)) ||
title;
return (
<div className={classes(['TitleBar', className])}>
{(status === undefined && (
<Icon className="TitleBar__statusIcon" name="tools" opacity={0.5} />
)) || (
<Icon
className="TitleBar__statusIcon"
color={statusToColor(status)}
name="eye"
/>
)}
<div
className="TitleBar__dragZone"
onMouseDown={(e) => fancy && onDragStart && onDragStart(e)}
/>
<div className="TitleBar__title">
{finalTitle}
{!!children && <div className="TitleBar__buttons">{children}</div>}
</div>
{process.env.NODE_ENV !== 'production' && (
<div
className="TitleBar__devBuildIndicator"
onClick={() => dispatch(toggleKitchenSink())}
>
<Icon name="bug" />
</div>
)}
{Boolean(fancy && canClose) && (
<div className="TitleBar__close TitleBar__clickable" onClick={onClose}>
×
</div>
)}
</div>
);
};
+4 -4
View File
@@ -5,7 +5,7 @@
"dependencies": {
"@popperjs/core": "^2.11.8",
"@types/marked": "4.3.2",
"@types/react": "^18.3.12",
"@types/react": "^19.1.0",
"common": "workspace:*",
"dateformat": "^5.0.3",
"dompurify": "^3.2.4",
@@ -14,10 +14,10 @@
"jest": "^29.7.0",
"js-yaml": "^4.1.0",
"marked": "^4.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-popper": "^2.3.0",
"tgui-core": "^1.8.4",
"tgui-core": "^2.0.5",
"tgui-dev-server": "workspace:*"
}
}
@@ -3,6 +3,11 @@
* SPDX-License-Identifier: MIT
*/
.candystripe:nth-child(odd) {
background-color: hsla(0, 0%, 0%, 0.25);
/* Using :where for 0 specificity - https://developer.mozilla.org/en-US/docs/Web/CSS/:where */
:where(.candystripe:nth-child(odd)) {
background-color: var(--candystripe-odd);
}
:where(.candystripe:nth-child(even)) {
background-color: var(--candystripe-even);
}
+7 -6
View File
@@ -5,17 +5,18 @@
@use '../colors.scss';
$fg-map: colors.$fg-map !default;
$bg-map: colors.$bg-map !default;
$map-keys: colors.$color-map !default;
@each $color-name, $color-value in $fg-map {
@each $color-name, $color-value in $map-keys {
.color-#{$color-name} {
color: $color-value !important;
color: hsl(from $color-value h s calc(l + var(--adjust-color))) !important;
}
}
@each $color-name, $color-value in $bg-map {
@each $color-name, $color-value in $map-keys {
.color-bg-#{$color-name} {
background-color: $color-value !important;
background-color: hsl(
from $color-value h s calc(l - var(--adjust-color))
) !important;
}
}
+21 -6
View File
@@ -1,12 +1,27 @@
@use '../colors.scss';
/**
* Copyright (c) 2021 Celotajs (https://github.com/celotajstg)
* SPDX-License-Identifier: MIT
*/
a {
&:link,
&:visited {
color: colors.$blue;
}
cursor: var(--cursor-pointer);
color: var(--color-hyperlink);
transition: color var(--transition-time-medium);
text-decoration: none;
&:hover,
&:active {
color: colors.$primary;
color: hsl(from var(--color-hyperlink) h s calc(l + var(--adjust-hover)));
}
&:visited {
color: var(--color-hyperlink-visited);
&:hover,
&:active {
color: hsl(
from var(--color-hyperlink-visited) h s calc(l + var(--adjust-hover))
);
}
}
}
@@ -37,11 +37,11 @@
outline-style: outset !important;
}
$fg-map: colors.$fg-map !default;
$bg-map: colors.$bg-map !default;
$map-keys: colors.$color-map !default;
@each $color-name, $color-value in $fg-map {
@each $color-name, $color-value in $map-keys {
/* prettier-ignore */
.outline-color-#{$color-name} {
outline: 0.167rem solid $color-value !important;
outline: var(--border-thickness-small) solid hsl(from $color-value h s calc(l + var(--adjust-color))) !important;
}
}
+4 -15
View File
@@ -1,27 +1,16 @@
/**
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*
* If you're looking for a color palette,
* see tgui-core - https://github.com/tgstation/tgui-core/tree/main/styles
* Files: vars-colors.scss | vars-components.scss | vars-vaules.scss
*/
@use 'sass:color';
@use 'sass:math';
$color-fg: hsl(0, 0%, 100%) !default;
$color-bg: hsl(0, 0%, 14%) !default;
$color-bg-section: rgba(0, 0, 0, 0.33) !default;
$color-bg-grad-spread: 2% !default;
$color-bg-start: color.adjust(
$color-bg,
$lightness: $color-bg-grad-spread
) !default;
$color-bg-end: color.adjust(
$color-bg,
$lightness: -$color-bg-grad-spread
) !default;
$unit: 12px;
$font-size: 1 * $unit !default;
$border-radius: 0.16em !default;
@function em($px) {
@return 1em * math.div($px, $unit);
+44 -74
View File
@@ -1,88 +1,58 @@
/**
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*
* If you're looking for a color palette,
* see tgui-core - https://github.com/tgstation/tgui-core/tree/main/styles
* Files: vars-colors.scss | vars-components.scss | vars-vaules.scss
*/
@use 'sass:color';
@use 'sass:map';
@use 'sass:meta';
// Base colors
$black: hsl(0, 0%, 0%) !default;
$white: hsl(0, 0%, 100%) !default;
$red: hsl(0, 72%, 50%) !default;
$orange: hsl(24, 89%, 54%) !default;
$yellow: hsl(52, 97%, 52%) !default;
$olive: hsl(68, 76%, 45%) !default;
$green: hsl(136, 70%, 41%) !default;
$teal: hsl(178, 100%, 35%) !default;
$blue: hsl(208, 65%, 47%) !default;
$violet: hsl(259, 60%, 50%) !default;
$purple: hsl(288, 60%, 49%) !default;
$pink: hsl(326, 71%, 56%) !default;
$brown: hsl(24, 47%, 45%) !default;
$grey: hsl(0, 0%, 47%) !default;
$light-grey: hsl(0, 0%, 67%) !default;
// Mappings of color names
$color-map: ();
$_gen_map: (
'black': var(--color-black),
'white': var(--color-white),
'red': var(--color-red),
'orange': var(--color-orange),
'yellow': var(--color-yellow),
'olive': var(--color-olive),
'green': var(--color-green),
'teal': var(--color-teal),
'blue': var(--color-blue),
'violet': var(--color-violet),
'purple': var(--color-purple),
'pink': var(--color-pink),
'brown': var(--color-brown),
'grey': var(--color-grey),
'gray': var(--color-grey),
'light-grey': var(--color-light-grey),
'light-gray': var(--color-light-grey),
'good': var(--color-good),
'average': var(--color-average),
'bad': var(--color-bad),
'label': var(--color-label),
);
$low-contrast-color-map: ('yellow', 'white');
$primary: hsl(210, 37%, 46%) !default;
$good: hsl(94, 63%, 41%) !default;
$average: hsl(33, 89%, 50%) !default;
$bad: hsl(0, 72%, 50%) !default;
$label: hsl(210, 18%, 58%) !default;
// Background and foreground color lightness ratios
$bg-lightness: -15% !default;
$fg-lightness: 10% !default;
// Color names for which to generate a color map
$color-map-keys: map.keys($_gen_map) !default;
@each $color-name in $color-map-keys {
// prettier-ignore
$color-map: map.merge($color-map, (
$color-name: map.get($_gen_map, $color-name),
));
}
/**
* Background and foreground color lightness ratios
* @deprecated
*/
@function bg($color) {
@return color.scale($color, $lightness: $bg-lightness);
@return hsl(from $color h s calc(l - var(--adjust-color)));
}
@function fg($color) {
@return color.scale($color, $lightness: $fg-lightness);
}
// Mappings of color names
$_gen_map: (
'black': $black,
'white': $white,
'red': $red,
'orange': $orange,
'yellow': $yellow,
'olive': $olive,
'green': $green,
'teal': $teal,
'blue': $blue,
'violet': $violet,
'purple': $purple,
'pink': $pink,
'brown': $brown,
'grey': $grey,
'light-grey': $light-grey,
'good': $good,
'average': $average,
'bad': $bad,
'label': $label,
);
// Foreground color names for which to generate a color map
$fg-map-keys: map.keys($_gen_map) !default;
// Background color names for which to generate a color map
$bg-map-keys: map.keys($_gen_map) !default;
$fg-map: ();
@each $color-name in $fg-map-keys {
// prettier-ignore
$fg-map: map.merge($fg-map, (
$color-name: fg(map.get($_gen_map, $color-name)),
));
}
$bg-map: ();
@each $color-name in $bg-map-keys {
// prettier-ignore
$bg-map: map.merge($bg-map, (
$color-name: bg(map.get($_gen_map, $color-name)),
));
@return hsl(from $color h s calc(l + var(--adjust-color)));
}
@@ -1,5 +1,3 @@
$color-background: hsla(0, 0%, 0%, 0.33) !default;
.NanoMap__container {
overflow: hiddden;
width: 100%;
@@ -14,7 +12,7 @@ $color-background: hsla(0, 0%, 0%, 0.33) !default;
.NanoMap__zoomer {
z-index: 20;
background-color: $color-background;
background-color: hsla(0, 0%, 0%, 0.33);
position: absolute;
top: 40px;
left: 0;
@@ -0,0 +1,27 @@
/**
* Internal variables
* For more, see: https://github.com/tgstation/tgui-core
* Files: vars-colors.scss | vars-components.scss | vars-vaules.scss
*/
:root {
/* TitleBar */
--titlebar-background: var(--color-secondary);
--titlebar-text: var(--color-text-translucent-light);
--titlebar-shadow-color: var(--color-border-dark);
--titlebar-shadow-core: var(--color-border-dark);
/* Camera Console */
--camera-console-background: hsla(0, 0%, 0%, 0.33);
/* ID Card */
--id-separator-color: var(--color-primary);
/* Tinder Messaging */
--tinder-sent-color: hsl(96, 63%, 35%);
--tinder-received-color: hsl(34, 88%, 43%);
/* Turbolift */
--turbolift-background: hsla(0, 100%, 50%, 0.35);
--turbolift-separator: hsla(0, 100%, 50%, 1);
}
+5 -48
View File
@@ -3,15 +3,9 @@
* SPDX-License-Identifier: MIT
*/
@use 'sass:color';
@use 'sass:map';
@use 'sass:math';
@use 'sass:meta';
// Type-casting
// --------------------------------------------------------
// Get a unit-less numeric value
/* Type-casting: Get a unit-less numeric value */
@function num($value) {
@if meta.type-of($value) != number {
@error 'Could not convert `#{$value}` - must be `type-of number`';
@@ -23,45 +17,8 @@
@return math.div($value, $value * 0 + 1);
}
// Color
// --------------------------------------------------------
// Returns the NTSC luminance of `$color` as a float (between 0 and 1).
// 1 is pure white, 0 is pure black.
@function luminance($color) {
$colors: (
'red': color.channel($color, 'red', $space: rgb),
'green': color.channel($color, 'green', $space: rgb),
'blue': color.channel($color, 'blue', $space: rgb),
);
@each $name, $value in $colors {
$adjusted: 0;
$value: math.div($value, 255);
@if $value < 0.03928 {
$value: math.div($value, 12.92);
} @else {
$value: math.div($value + 0.055, 1.055);
$value: math.pow($value, 2.4);
}
// prettier-ignore
$colors: map.merge($colors, (
$name: $value,
));
}
// prettier-ignore
@return (map.get($colors, 'red') * .2126)
+ (map.get($colors, 'green') * .7152)
+ (map.get($colors, 'blue') * .0722);
}
// Blends an RGBA color with a static background color based on its
// alpha channel. Returns an RGB color, which is compatible with IE8.
@function fake-alpha($color-rgba, $color-background) {
@return color.mix(
color.change($color-rgba, $alpha: 1),
$color-background,
color.alpha($color-rgba) * 100%
);
// Multiplies our viewport units by the DPI scaling amount
// to ensure that they display correctly when using differently-scaled windows
@function vp($viewportUnit) {
@return calc(var(--scaling-amount) * $viewportUnit);
}
@@ -17,14 +17,14 @@
.AlertModal__Loader {
width: 100%;
position: relative;
height: 4px;
height: var(--border-thickness-large);
}
.AlertModal__LoaderProgress {
position: absolute;
transition:
background-color 500ms ease-out,
width 500ms ease-out;
background-color: colors.bg(colors.$primary);
transition-property: background-color, width;
transition-duration: var(--transition-time-slow);
transition-timing-function: ease-out;
background-color: var(--color-primary);
height: 100%;
}
@@ -1,7 +1,5 @@
@use '../base.scss';
$background-color: hsla(0, 0%, 0%, 0.33) !default;
.CameraConsole__left {
position: absolute;
top: 0;
@@ -16,7 +14,7 @@ $background-color: hsla(0, 0%, 0%, 0.33) !default;
bottom: 0;
left: base.em(220px);
right: 0;
background-color: $background-color;
background-color: var(--camera-console-background);
}
.CameraConsole__toolbar {
@@ -4,7 +4,7 @@
}
&__Cell {
padding: 3px 0;
padding: var(--space-s) 0;
&--Icon {
width: 25px;
@@ -1,15 +1,13 @@
@use '../colors.scss';
$department_map: (
'Command': colors.$yellow,
'Security': colors.$red,
'Engineering': colors.$orange,
'Medical': colors.$teal,
'Misc': colors.$white,
'Science': colors.$purple,
'Supply': colors.$brown,
'Service': colors.$green,
'Silicon': colors.$pink,
'Command': var(--color-yellow),
'Security': var(--color-red),
'Engineering': var(--color-orange),
'Medical': var(--color-teal),
'Misc': var(--color-white),
'Science': var(--color-purple),
'Supply': var(--color-brown),
'Service': var(--color-green),
'Silicon': var(--color-pink),
);
.CrewManifest {
@@ -27,32 +25,32 @@ $department_map: (
}
&__Cell {
padding: 3px 0;
padding: var(--space-s) 0;
&--Rank {
color: colors.$label;
color: var(--color-label);
}
}
&__Icons {
padding: 3px 9px;
padding: var(--space-s) var(--space-l);
text-align: right;
}
&__Icon {
color: colors.$label;
color: var(--color-label);
position: relative;
&:not(:last-child) {
margin-right: 7px;
margin-right: var(--space-m);
}
&--Chevron {
padding-right: 2px;
padding-right: var(--space-xs);
}
&--Command {
color: colors.$yellow;
color: var(--color-yellow);
}
}
}
@@ -1,13 +1,13 @@
.ExperimentTechwebServer__Web,
.ExperimentConfigure__ExperimentPanel {
background: hsl(0, 0%, 0%);
border: 1px solid hsl(212, 37%, 40%);
margin: 3px 0;
background: var(--color-black);
border: var(--border-thickness-tiny) solid var(--color-primary);
margin: var(--space-s) 0;
}
.ExperimentTechwebServer__WebHeader {
background: hsl(212, 37%, 40%);
padding: 2px;
background: var(--color-primary);
padding: var(--space-xs);
}
.ExperimentTechwebServer__WebName {
@@ -15,11 +15,11 @@
}
.ExperimentTechwebServer__WebContent {
padding: 4px;
padding: var(--space-sm);
}
.ExperimentTechwebServer__WebContent > .LabeledList {
margin: 0.25rem 0.25rem 0.25rem 1rem;
margin: var(--space-s) var(--space-s) var(--space-s) var(--space-xl);
}
.ExperimentConfigure__ExperimentName {
@@ -28,12 +28,13 @@
}
.ExperimentConfigure__ExperimentContent {
padding: 0.25rem 1.5rem 0.25rem 0.25rem;
/* prettier-ignore */
padding: var(--space-s) calc(var(--space-xl) * 1.5) var(--space-s) var(--space-s);
}
.ExperimentStage__Indicator {
font-weight: bold;
margin-right: 1rem;
margin-right: var(--space-xl);
text-align: center;
}
@@ -43,17 +44,17 @@
}
.ExperimentStage__StageContainer {
margin-bottom: 5px;
margin-bottom: var(--space-m);
}
.ExperimentStage__Table {
border-collapse: separate;
border-spacing: 0.25rem 0.25rem;
border-spacing: var(--space-s) var(--space-s);
}
.ExperimentConfigure__PerformExperiment {
text-align: center;
padding: 0.75rem 0;
padding: var(--space-l) 0;
}
.ExperimentConfigure__ExperimentsContainer {
@@ -64,7 +65,6 @@
.ExperimentConfigure__ExperimentsContainer > :last-child {
flex: 1;
overflow-y: auto;
}
// Required for the time being otherwise we'll end up coloring the tooltip
@@ -81,5 +81,5 @@
height: 100%;
right: 0;
top: 0;
color: hsla(0, 0%, 100%, 0.5);
color: var(--color-text-translucent);
}
@@ -2,14 +2,12 @@
@use '../base.scss';
@use '../colors.scss';
$color-separator: colors.$primary !default;
.IDCard__NamePlate {
margin-left: -6px;
margin-right: -6px;
margin-top: 6px;
padding: 0.5em;
border-top: base.em(2px) solid $color-separator;
border-top: base.em(2px) solid var(--id-separator-color);
font-size: base.em(14px);
font-weight: bold;
}

Some files were not shown because too many files have changed in this diff Show More