diff --git a/src/config.ts b/src/config.ts index ca0e2cd8..82684bbf 100644 --- a/src/config.ts +++ b/src/config.ts @@ -42,6 +42,11 @@ export interface FatexConfig { global: { useMarkdown: boolean; + styles: { + name: string; + customProperty: string; + defaultValue: string; + }[]; }; } @@ -73,5 +78,52 @@ export const FateX: FatexConfig = { }, global: { useMarkdown: false, - }, + styles: [ + { + name: "buttonShadowColor", + customProperty: "--fatex-button-shadow-color", + defaultValue: "#a0a0a0" + }, + { + name: "headerBackgroundColor", + customProperty: "--fatex-header-color", + defaultValue: "#2f3542" + }, + { + name: "headerTextColor", + customProperty: "--fatex-header-text-color", + defaultValue: "#ffffff" + }, + { + name: "mainShadowColor", + customProperty: "--fatex-main-shadow-color", + defaultValue: "#2f3542" + }, + { + name: "primarySheetColor", + customProperty: "--fatex-primary-color", + defaultValue: "#2f3542" + }, + { + name: "scrollbarColor", + customProperty: "--fatex-scrollbar-color", + defaultValue: "#2f3542" + }, + { + name: "sheetBackgroundColor", + customProperty: "--fatex-sheet-background-color", + defaultValue: "#f1f2f6" + }, + { + name: "textColor1", + customProperty: "--fatex-text-color-1", + defaultValue: "#191813" + }, + { + name: "textColor2", + customProperty: "--fatex-text-color-2", + defaultValue: "#ffffff" + } + ] + } }; diff --git a/src/fatex.ts b/src/fatex.ts index 4a2cdc53..a96942df 100644 --- a/src/fatex.ts +++ b/src/fatex.ts @@ -27,6 +27,7 @@ import { SkillSheet } from "./module/item/skill/SkillSheet"; import { StressSheet } from "./module/item/stress/StressSheet"; import { StuntSheet } from "./module/item/stunt/StuntSheet"; import { TemplateActorsFeature } from "./module/features/TemplateActorsFeature"; +import { ThemeConfigurationFeature } from "./module/features/ThemeConfigurationFeature"; import { GroupSheet } from "./module/actor/sheets/GroupSheet"; import { ActorGroupFeature } from "./module/features/ActorGroupFeature"; import { ReferenceSheet } from "./module/item/references/ReferenceSheet"; @@ -117,6 +118,7 @@ Hooks.once("init", async () => { /* Register hooks */ /* -------------------------------- */ TemplateActorsFeature.hooks(); +ThemeConfigurationFeature.hooks() ActorGroupFeature.hooks(); /* -------------------------------- */ diff --git a/src/module/components/Configuration/ThemeConfiguration.ts b/src/module/components/Configuration/ThemeConfiguration.ts new file mode 100644 index 00000000..95addc3f --- /dev/null +++ b/src/module/components/Configuration/ThemeConfiguration.ts @@ -0,0 +1,102 @@ +// @ts-nocheck + +export class ThemeConfig extends FormApplication { + currentStyles: { [key: string]: string | undefined }; + changesSaved: boolean; + + constructor() { + super(); + this.currentStyles = $(":root").css(CONFIG.FateX.global.styles.map((x) => x.customProperty)); + this.changesSaved = false; + } + + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + title: "Theme Configuration", + id: "themeConfig", + template: "/systems/fatex/templates/apps/theme-config.hbs", + width: 600, + height: "auto", + closeOnSubmit: true, + } as BaseEntitySheet.Options); + } + + async _updateObject() { + const updates = CONFIG.FateX.global.styles.reduce((properties, style) => { + const key = `flags.fatex.${style.name}`; + properties[key] = $(":root").css(style.customProperty) ?? style.defaultValue; + + return properties; + }, {}); + + return game.user.update(updates); + } + + activateListeners(html: JQuery) { + super.activateListeners(html); + + html.find(`[type="color"]`).on("change", this.onChange.bind(this)); + html.find(`button[name="reset"]`).on("click", this.reset.bind(this)); + html.find(`button[name="submit"]`).on("click", this.saveChanges.bind(this)); + html.find(`button[name="cancel"]`).on("click", this.close.bind(this)); + } + + getData(options?: Application.RenderOptions): FormApplication.Data, FormApplication.Options> { + const customPropertyValues = $(":root").css(CONFIG.FateX.global.styles.map((x) => x.customProperty)); + + // Create a new object where the custom property values are assigned to keys + // matching the component names used in the templates and default styles config. + const customProperties = Object.assign( + ...CONFIG.FateX.global.styles.map(({ name, customProperty }) => ({ [name]: customPropertyValues[customProperty] })) + ); + + // Filter out any custom properties which are currently undefined. + const definedCustomProperties = Object.fromEntries(Object.entries(customProperties).filter(([_, value]) => value !== undefined)); + + const defaultStyles = Object.assign(...CONFIG.FateX.global.styles.map(({ name, defaultValue }) => ({ [name]: defaultValue }))); + + // Create a new object where the default styles fill in any values not defined + // by CSS custom properties. + const currentValues = { ...defaultStyles, ...definedCustomProperties }; + + return mergeObject(super.getData(options), currentValues); + } + + onChange(event: JQuery.Event) { + const newValue = event.currentTarget.value; + const componenetName = $(event.currentTarget).data("edit"); + const customProperty = CONFIG.FateX.global.styles.find((x) => x.name === componenetName)?.customProperty; + + // Update the custom property associated with the colour selector to the chosen value. + $(":root").css(customProperty, newValue); + } + + reset() { + // Loop over the custom properties in the config file and set each of them + // to "unset". This will cause the fallback values to take effect, which + // align with the system defaults. + CONFIG.FateX.global.styles.forEach(({ customProperty }) => { + $(":root").css(customProperty, "unset"); + }); + + // Rerender the sheet so that the default styles will be applied due to the + // lack of set custom properties. + this.render(); + } + + saveChanges() { + this.changesSaved = true; + } + + async close(options?: FormApplication.CloseOptions): Promise { + if (!this.changesSaved) { + // Loops over the user's original property values and undoes any changes + // they've made. Exiting via the save button will prevent this reset. + for (const [property, value] of Object.entries(this.currentStyles)) { + $(":root").css(property, value ?? "unset"); + } + } + + await super.close(options); + } +} diff --git a/src/module/features/ThemeConfigurationFeature.ts b/src/module/features/ThemeConfigurationFeature.ts new file mode 100644 index 00000000..dcd1d673 --- /dev/null +++ b/src/module/features/ThemeConfigurationFeature.ts @@ -0,0 +1,13 @@ +export class ThemeConfigurationFeature { + static hooks() { + Hooks.once("ready", () => { + // Set user defined CSS custom properties + CONFIG.FateX.global.styles.forEach(({ name, customProperty }) => { + // Retrieve the value stored in a user flag is there is one. + const value = game?.user?.getFlag("fatex", name) as string | undefined; + + $(":root").css(customProperty, value ?? "unset"); + }) + }); + } +} diff --git a/src/module/helper/Settings.ts b/src/module/helper/Settings.ts index e7d82797..1071913e 100644 --- a/src/module/helper/Settings.ts +++ b/src/module/helper/Settings.ts @@ -1,5 +1,16 @@ +import { ThemeConfig } from "../components/Configuration/ThemeConfiguration"; + export class FateXSettings { static registerSettings() { + game.settings.registerMenu("fatex", "theme", { + name: "Theme Settings", + label: "Configure Theme", + hint: "Allows a user to select custom color schemes for the FateX interface.", + icon: "fas fa-cog", + type: ThemeConfig, + restricted: false + }); + game.settings.register("fatex", "enableAlphaFeatures", { name: game.i18n.localize("FAx.Settings.System.Alpha.Name"), hint: game.i18n.localize("FAx.Settings.System.Alpha.Hint"), @@ -9,4 +20,4 @@ export class FateXSettings { default: false, }); } -} +} \ No newline at end of file diff --git a/src/styles/abstract/mixins.scss b/src/styles/abstract/mixins.scss index 04c24dec..0a59ad47 100644 --- a/src/styles/abstract/mixins.scss +++ b/src/styles/abstract/mixins.scss @@ -3,7 +3,7 @@ position: absolute; top: -1px; left: -1px; - border-top: $size solid #f1f2f6; + border-top: $size solid $fatex-sheet-background-color; border-right: $size solid transparent; } @@ -12,7 +12,7 @@ position: absolute; top: -1px; right: -1px; - border-top: $size solid #f1f2f6; + border-top: $size solid $fatex-sheet-background-color; border-left: $size solid transparent; } @@ -21,7 +21,7 @@ position: absolute; bottom: -1px; right: -1px; - border-bottom: $size solid #f1f2f6; + border-bottom: $size solid $fatex-sheet-background-color; border-left: $size solid transparent; } diff --git a/src/styles/abstract/variables.scss b/src/styles/abstract/variables.scss index 941881f7..e45e3bc1 100644 --- a/src/styles/abstract/variables.scss +++ b/src/styles/abstract/variables.scss @@ -2,16 +2,16 @@ $component-padding: 10px; // Colors -$primary-color: rgba(47, 53, 66, 1); +$primary-color: #2f3542; -$sheet-background: rgb(241, 242, 246); +$sheet-background: #f1f2f6; $message-background: transparentize($primary-color, 0.7); $primary-text-color: #191813; $light-text-color: #fff; -$caution-color: rgb(242, 22, 40); -$shadow-color: rgb(160, 160, 160); +$caution-color: #f21628; +$shadow-color: #a0a0a0; // Fonts $primary-font: "Montserrat", sans-serif; @@ -21,3 +21,11 @@ $fatex-header-color: var(--fatex-header-color, $primary-color); $fatex-header-text-color: var(--fatex-header-text-color, $light-text-color); $fatex-primary-color: var(--fatex-primary-color, $primary-color); +$fatex-sheet-background-color: var(--fatex-sheet-background-color, $sheet-background); + +$fatex-text-color-1: var(--fatex-text-color-1, $primary-text-color); +$fatex-text-color-2: var(--fatex-text-color-2, $light-text-color); + +$fatex-main-shadow-color: var(--fatex-main-shadow-color, $primary-color); +$fatex-button-shadow-color: var(--fatex-button-shadow-color, $shadow-color); +$fatex-scrollbar-color: var(--fatex-scrollbar-color, $primary-color); diff --git a/src/styles/base/foundry-ui.scss b/src/styles/base/foundry-ui.scss index db831129..f0953c64 100644 --- a/src/styles/base/foundry-ui.scss +++ b/src/styles/base/foundry-ui.scss @@ -4,10 +4,9 @@ .window-app .window-content, #chat-log .message, -#chat-form textarea, #chat-controls div.roll-type-select select, -.sidebar-tab .directory-header .header-search input, -#chat-form .cm-s-easymde { - background: $sheet-background; - color: var(--fatex-primary-text-color, $primary-text-color); +#chat-form .cm-s-easymde, +.chat-message .message-header { + background: $fatex-sheet-background-color; + color: $fatex-text-color-1; } diff --git a/src/styles/components/actions.scss b/src/styles/components/actions.scss index 6c6a0598..ce34a206 100644 --- a/src/styles/components/actions.scss +++ b/src/styles/components/actions.scss @@ -4,7 +4,7 @@ align-items: center; gap: 10px; height: 100%; - text-shadow: 1px 1px 2px $shadow-color; + text-shadow: 1px 1px 2px $fatex-button-shadow-color; pointer-events: none; z-index: 4; @@ -58,7 +58,7 @@ gap: 0; font-size: 16px; color: $fatex-primary-color; - text-shadow: 1px -1px 1px $sheet-background; + text-shadow: 1px -1px 1px $fatex-sheet-background-color; } &__icon { @@ -92,12 +92,12 @@ .fatex-js-edit-mode { .fatex-actions--headline, .fatex-actions--skill { - background: linear-gradient(90deg, rgba(47, 53, 66, 0) 0%, #2f3542 33%, #2f3542 100%); + background: linear-gradient(90deg, transparent, $fatex-primary-color 33%, $fatex-primary-color 100%); } .fatex-actions--item, .fatex-actions--section-heading { - background: linear-gradient(90deg, transparentize($sheet-background, 1) 0%, $sheet-background 33%, $sheet-background 100%); + background: linear-gradient(90deg, transparent 0%, $fatex-sheet-background-color 33%, $fatex-sheet-background-color 100%); } .fatex-actions__icon { diff --git a/src/styles/components/actor-group/actor-group.scss b/src/styles/components/actor-group/actor-group.scss index eeb05eb2..9f760d50 100644 --- a/src/styles/components/actor-group/actor-group.scss +++ b/src/styles/components/actor-group/actor-group.scss @@ -38,7 +38,7 @@ font-weight: bold; text-transform: uppercase; font-size: 13px; - box-shadow: 1px 1px 1px $shadow-color; + box-shadow: 1px 1px 1px $fatex-button-shadow-color; &.active, &:hover { diff --git a/src/styles/components/apps/setup.scss b/src/styles/components/apps/setup.scss index 6a277988..ec9da7fd 100644 --- a/src/styles/components/apps/setup.scss +++ b/src/styles/components/apps/setup.scss @@ -75,7 +75,7 @@ border: 1px solid $fatex-primary-color; border-radius: 3px; margin-right: $component-padding; - color: var(--fatex-light-text-color, $light-text-color); + color: $fatex-text-color-2; font-size: 11px; text-align: center; } diff --git a/src/styles/components/checkbox.scss b/src/styles/components/checkbox.scss index 3bff4c0a..a8f0bc76 100644 --- a/src/styles/components/checkbox.scss +++ b/src/styles/components/checkbox.scss @@ -14,7 +14,7 @@ transform: translate(-60%, -40%); font-weight: 900; font-size: 24px; - text-shadow: 1px 1px 1px $sheet-background; + text-shadow: 1px 1px 1px $fatex-sheet-background-color; } &__icon { diff --git a/src/styles/components/desk.scss b/src/styles/components/desk.scss index e01bb934..d728346c 100644 --- a/src/styles/components/desk.scss +++ b/src/styles/components/desk.scss @@ -19,7 +19,6 @@ &__content { grid-area: content; overflow-y: auto; - scrollbar-width: thin; &--app { padding: $component-padding; @@ -49,7 +48,7 @@ &__sidebar { min-width: 240px; - box-shadow: 12px 0 15px 0 $fatex-primary-color; + box-shadow: 12px 0 15px 0 $fatex-main-shadow-color; } &__tabloid { diff --git a/src/styles/components/dialog.scss b/src/styles/components/dialog.scss index 91fd004a..eb207c9c 100644 --- a/src/styles/components/dialog.scss +++ b/src/styles/components/dialog.scss @@ -7,7 +7,7 @@ .window-content { padding: $component-padding; - background: $sheet-background; + background: $fatex-sheet-background-color; } .dialog-buttons { diff --git a/src/styles/components/header.scss b/src/styles/components/header.scss index 871f8826..f88fab4c 100644 --- a/src/styles/components/header.scss +++ b/src/styles/components/header.scss @@ -9,7 +9,7 @@ font-size: 23px; color: $fatex-header-text-color; background: $fatex-header-color; - box-shadow: 0 2px 15px 0 $fatex-header-color; + box-shadow: 0 2px 15px 0 $fatex-main-shadow-color; z-index: 5; &__combine { diff --git a/src/styles/components/headline.scss b/src/styles/components/headline.scss index a3914958..06545879 100644 --- a/src/styles/components/headline.scss +++ b/src/styles/components/headline.scss @@ -1,7 +1,7 @@ .fatex-headline { position: relative; margin-bottom: 0.5rem; - color: var(--fatex-light-text-color, $light-text-color); + color: $fatex-text-color-2; background: $fatex-primary-color; &::before { @@ -51,7 +51,7 @@ z-index: 100; transform: translate(-25px, 0px); font-weight: 900; - color: $sheet-background; + color: $fatex-sheet-background-color; -webkit-text-stroke: 2px $fatex-primary-color; text-shadow: initial; @@ -59,7 +59,7 @@ left: initial; right: 100%; font-size: 24px; - text-shadow: 1px 1px 1px $sheet-background; + text-shadow: 1px 1px 1px $fatex-sheet-background-color; transform: translate(15px, -7px); } @@ -90,7 +90,7 @@ .fatex-section-heading { display: block; position: relative; - color: $primary-text-color; + color: $fatex-text-color-1; &--no-border { border: none; diff --git a/src/styles/components/inline-tabs.scss b/src/styles/components/inline-tabs.scss index 2e0b7b04..7e8b4256 100644 --- a/src/styles/components/inline-tabs.scss +++ b/src/styles/components/inline-tabs.scss @@ -14,7 +14,7 @@ &.active { background: $fatex-primary-color; - color: $sheet-background; + color: $fatex-sheet-background-color; border: none; } } diff --git a/src/styles/components/input.scss b/src/styles/components/input.scss index 86d6548c..1afac849 100644 --- a/src/styles/components/input.scss +++ b/src/styles/components/input.scss @@ -40,7 +40,7 @@ input[type="text"].fatex-text-input { font-weight: 900; font-size: 24px; color: $fatex-primary-color; - text-shadow: 1px 1px 1px $sheet-background; + text-shadow: 1px 1px 1px $fatex-sheet-background-color; } &__label { @@ -70,7 +70,7 @@ input[type="number"].fatex-text-input--headline { padding: 5px; font-size: 13px; font-weight: bold; - color: var(--fatex-light-text-color, $light-text-color); + color: $fatex-text-color-2; text-transform: uppercase; text-align: center; border: none; diff --git a/src/styles/components/radio.scss b/src/styles/components/radio.scss index 8b3e8c99..51170a71 100644 --- a/src/styles/components/radio.scss +++ b/src/styles/components/radio.scss @@ -44,7 +44,7 @@ color: $fatex-primary-color; font-weight: 900; font-size: 24px; - text-shadow: 1px 1px 1px $sheet-background; + text-shadow: 1px 1px 1px $fatex-sheet-background-color; &--active { background: none; diff --git a/src/styles/components/scrollbar.scss b/src/styles/components/scrollbar.scss index 888df085..8c704186 100644 --- a/src/styles/components/scrollbar.scss +++ b/src/styles/components/scrollbar.scss @@ -1,22 +1,22 @@ -::-webkit-scrollbar { +.fatex ::-webkit-scrollbar { width: 6px; } -::-webkit-scrollbar-track { +.fatex ::-webkit-scrollbar-track { box-shadow: 0 0 1px #999 inset; border-radius: 4px; } -::-webkit-scrollbar-thumb { +.fatex ::-webkit-scrollbar-thumb { outline: none; border-radius: 3px; - background: $primary-color !important; + background: $fatex-scrollbar-color !important; border: 0; } -:root { +.fatex * { scrollbar-width: thin !important; - scrollbar-color: $primary-color $sheet-background !important; + scrollbar-color: $fatex-scrollbar-color $fatex-sheet-background-color !important; } input[type="range"]::-webkit-slider-thumb { diff --git a/src/styles/components/sheet/configuration.scss b/src/styles/components/sheet/configuration.scss index 4c1d48f4..38c36c20 100644 --- a/src/styles/components/sheet/configuration.scss +++ b/src/styles/components/sheet/configuration.scss @@ -7,7 +7,7 @@ box-shadow: 0 -2px 15px 0 #2f3542; background: #2f3542; z-index: 5; - color: var(--fatex-light-text-color, $light-text-color); + color: $fatex-text-color-2; .fatex-js-edit-mode & { display: block; diff --git a/src/styles/components/sheet/sheet.scss b/src/styles/components/sheet/sheet.scss index 5550d27e..b55351cd 100644 --- a/src/styles/components/sheet/sheet.scss +++ b/src/styles/components/sheet/sheet.scss @@ -15,7 +15,7 @@ .window-content { padding: 0; - background: $sheet-background; + background: $fatex-sheet-background-color; overflow-y: hidden; } diff --git a/src/styles/components/slider.scss b/src/styles/components/slider.scss index 4124f0c8..399e839e 100644 --- a/src/styles/components/slider.scss +++ b/src/styles/components/slider.scss @@ -8,7 +8,7 @@ font-size: 24px; font-weight: 900; text-align: center; - text-shadow: 1px 1px 1px $sheet-background; + text-shadow: 1px 1px 1px $fatex-sheet-background-color; background: none; border: none; } diff --git a/src/styles/components/tabs/tab-navigation.scss b/src/styles/components/tabs/tab-navigation.scss index 2cabb98b..2ecc12dd 100644 --- a/src/styles/components/tabs/tab-navigation.scss +++ b/src/styles/components/tabs/tab-navigation.scss @@ -15,7 +15,7 @@ &.active, &:hover { background: $fatex-primary-color; - color: var(--fatex-light-text-color, $light-text-color); + color: $fatex-text-color-2; } &::after { @@ -43,7 +43,7 @@ &.active, &:hover { font-weight: bold; - background: $sheet-background; + background: $fatex-sheet-background-color; border: 1px solid $fatex-primary-color; border-right: 0; opacity: 1; diff --git a/src/styles/fatex.scss b/src/styles/fatex.scss index 9a60b950..86f8216d 100644 --- a/src/styles/fatex.scss +++ b/src/styles/fatex.scss @@ -10,6 +10,6 @@ @import "utils/disabled"; @import "utils/effects"; -@import "utils/padding"; @import "utils/position"; @import "utils/sizing"; +@import "utils/spacing"; diff --git a/src/styles/legacy/chat.scss b/src/styles/legacy/chat.scss index 1efb197d..7eae1176 100644 --- a/src/styles/legacy/chat.scss +++ b/src/styles/legacy/chat.scss @@ -1,13 +1,13 @@ .fatex__headline { background: $fatex-primary-color; - color: var(--fatex-light-text-color, $light-text-color); + color: $fatex-text-color-2; padding: $component-padding/2 $component-padding * 2 $component-padding/2 $component-padding * 2; position: relative; font-weight: bold; text-transform: uppercase; text-align: center; font-size: 13px; - box-shadow: 1px 1px 1px $shadow-color; + box-shadow: 1px 1px 1px $fatex-button-shadow-color; &::before { @include cutout-top-left; @@ -33,7 +33,7 @@ transform: translate(-25px, 0px); font-weight: 900; font-size: 24px; - color: $sheet-background; + color: $fatex-sheet-background-color; -webkit-text-stroke: 2px $fatex-primary-color; text-shadow: initial; } diff --git a/src/styles/utils/padding.scss b/src/styles/utils/padding.scss deleted file mode 100644 index a0226363..00000000 --- a/src/styles/utils/padding.scss +++ /dev/null @@ -1,3 +0,0 @@ -.fatex-u-padding-std { - padding: $component-padding; -} diff --git a/src/styles/utils/spacing.scss b/src/styles/utils/spacing.scss new file mode 100644 index 00000000..773c05bf --- /dev/null +++ b/src/styles/utils/spacing.scss @@ -0,0 +1,11 @@ +.fatex-u-padding-std { + padding: $component-padding; +} + +.fatex-u-mb-l { + margin-bottom: 2 * $component-padding; +} + +.fatex-u-mt-std { + margin-top: $component-padding; +} diff --git a/system/templates/apps/theme-config.hbs b/system/templates/apps/theme-config.hbs new file mode 100644 index 00000000..e7825fb7 --- /dev/null +++ b/system/templates/apps/theme-config.hbs @@ -0,0 +1,198 @@ +
+
+

Header Styles

+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+
+ +
+

Core Sheet Styles

+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+

This should contrast the sheet background.

+
+ +
+ +
+ + +
+

This should contrast the primary sheet color.

+
+ +
+ +
+ + +
+

Controls the colour of the shadow for the header bar and the sidebar on actor sheets.

+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+
+ + +