Initial commit
This commit is contained in:
commit
c983d9b91b
20 changed files with 5729 additions and 0 deletions
16
.eslintrc.json
Normal file
16
.eslintrc.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"standard"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"indent": ["error", 4]
|
||||
}
|
||||
}
|
||||
BIN
.github/readme/token-action-hud.gif
vendored
Normal file
BIN
.github/readme/token-action-hud.gif
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5 MiB |
102
.github/workflows/main.yml
vendored
Normal file
102
.github/workflows/main.yml
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
name: Create Module Files For GitHub Release
|
||||
|
||||
env:
|
||||
# The URL used for the module's "Project URL" link on FoundryVTT's website.
|
||||
project_url: "https://github.com/${{github.repository}}"
|
||||
|
||||
# A URL that will always point to the latest manifest.
|
||||
# FoundryVTT uses this URL to check whether the current module version that
|
||||
# is installed is the latest version. This URL should NOT change,
|
||||
# otherwise FoundryVTT won't be able to perform this check.
|
||||
latest_manifest_url: "https://github.com/${{github.repository}}/releases/latest/download/module.json"
|
||||
|
||||
# The URL to the module archive associated with the module release being
|
||||
# processed by this workflow.
|
||||
release_module_url: "https://github.com/${{github.repository}}/releases/download/${{github.event.release.tag_name}}/module.zip"
|
||||
|
||||
on:
|
||||
# Only run this workflow when a release is published.
|
||||
# To modify this workflow when other events occur, see:
|
||||
# - https://docs.github.com/en/actions/using-workflows/triggering-a-workflow
|
||||
# - https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
|
||||
# - https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on
|
||||
#
|
||||
# Note that some steps may depend on context variables that are only
|
||||
# available for release events, so if you add other events, you may need to
|
||||
# alter other parts of this workflow.
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Extract version embedded in the tag.
|
||||
# This step expects the tag to be one of the following formats:
|
||||
# - "v<major>.<minor>.<patch>" (e.g., "v1.2.3")
|
||||
# - "<major>.<minor>.<patch>" (e.g., "1.2.3")
|
||||
#
|
||||
# The version will be used by later steps to fill in the value for the
|
||||
# "version" key required for a valid module manifest.
|
||||
- name: Extract Version From Tag
|
||||
id: get_version
|
||||
uses: battila7/get-version-action@v2
|
||||
|
||||
# Modify "module.json" with values specific to the release.
|
||||
# Since the values for the "version" and "url" keys aren't known ahead of
|
||||
# time, the manifest file in the repository is updated with these values.
|
||||
#
|
||||
# While this does modify the manifest file in-place, the changes are not
|
||||
# commited to the repository, and only exist in the action's filesystem.
|
||||
- name: Modify Module Manifest With Release-Specific Values
|
||||
id: sub_manifest_link_version
|
||||
uses: cschleiden/replace-tokens@v1
|
||||
with:
|
||||
files: 'module.json'
|
||||
env:
|
||||
VERSION: ${{steps.get_version.outputs.version-without-v}}
|
||||
URL: ${{ env.project_url }}
|
||||
MANIFEST: ${{ env.latest_manifest_url }}
|
||||
DOWNLOAD: ${{ env.release_module_url }}
|
||||
|
||||
# Create a "module.zip" archive containing all the module's required files.
|
||||
# If you have other directories or files that will need to be added to
|
||||
# your packaged module, add them here.
|
||||
- name: Create Module Archive
|
||||
run: |
|
||||
# Note that `zip` will only emit warnings when a file or directory
|
||||
# doesn't exist, it will not fail.
|
||||
zip \
|
||||
`# Options` \
|
||||
--recurse-paths \
|
||||
`# The name of the output file` \
|
||||
./module.zip \
|
||||
`# The files that will be included.` \
|
||||
module.json \
|
||||
readme.md \
|
||||
LICENSE \
|
||||
languages/ \
|
||||
scripts/ \
|
||||
styles/ \
|
||||
# Don't forget to add a backslash at the end of the line for any
|
||||
# additional files or directories!
|
||||
|
||||
# Update the GitHub release with the manifest and module archive files.
|
||||
- name: Update Release with Files
|
||||
id: create_version_release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
allowUpdates: true
|
||||
name: ${{ github.event.release.name }}
|
||||
draft: ${{ github.event.release.unpublished }}
|
||||
prerelease: ${{ github.event.release.prerelease }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
artifacts: './module.json, ./module.zip'
|
||||
tag: ${{ github.event.release.tag_name }}
|
||||
body: ${{ github.event.release.body }}
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
node_modules/*
|
||||
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"githubPullRequests.ignoredPullRequestBranches": [
|
||||
"master"
|
||||
]
|
||||
}
|
||||
20
languages/en.json
Normal file
20
languages/en.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"tokenActionHud": {
|
||||
"template": {
|
||||
"armor": "Armor",
|
||||
"containers": "Containers",
|
||||
"consumables": "Consumables",
|
||||
"equipment": "Equipment",
|
||||
"inventory": "Inventory",
|
||||
"item": "Item",
|
||||
"weapons": "Weapons",
|
||||
"treasure": "Treasure",
|
||||
"settings": {
|
||||
"displayUnequipped": {
|
||||
"hint": "Choose whether to display unequipped items on the HUD",
|
||||
"name": "Display Unequipped"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
72
module.json
Normal file
72
module.json
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
{
|
||||
"id": "token-action-hud-template",
|
||||
"title": "Token Action HUD Template",
|
||||
"description": "Token Action HUD is a repositionable HUD of actions for a selected token",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Larkinabout",
|
||||
"url": "https://github.com/Larkinabout"
|
||||
}
|
||||
],
|
||||
"url": "This is auto replaced",
|
||||
"flags": {},
|
||||
"version": "This is auto replaced",
|
||||
"compatibility": {
|
||||
"minimum": "11",
|
||||
"verified": "11.313"
|
||||
},
|
||||
"esmodules": [
|
||||
"./scripts/init.js"
|
||||
],
|
||||
"scripts": [
|
||||
],
|
||||
"styles": [
|
||||
"./styles/tah-template-style.css"
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "languages/en.json"
|
||||
}
|
||||
],
|
||||
"packs": [],
|
||||
"relationships": {
|
||||
"systems": [
|
||||
{
|
||||
"id": "template",
|
||||
"type": "system",
|
||||
"compatibility": [
|
||||
{
|
||||
"minimum": "1.0.0",
|
||||
"verified": "1.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"requires": [
|
||||
{
|
||||
"id": "token-action-hud-core",
|
||||
"type": "module",
|
||||
"compatibility": [
|
||||
{
|
||||
"minimum": "1.5.0",
|
||||
"maximum": "1.5",
|
||||
"verified": "1.5.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"optional": [],
|
||||
"flags": {
|
||||
"optional": []
|
||||
}
|
||||
},
|
||||
"socket": false,
|
||||
"manifest": "This is auto replaced",
|
||||
"download": "This is auto replaced",
|
||||
"readme": "https://github.com/Larkinabout/fvtt-token-action-hud-template#readme",
|
||||
"protected": false,
|
||||
"coreTranslation": false,
|
||||
"library": false
|
||||
}
|
||||
4462
package-lock.json
generated
Normal file
4462
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
16
package.json
Normal file
16
package.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"dev": "rollup -wcm"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-multi-entry": "^6.0.0",
|
||||
"eslint": "^8.25.0",
|
||||
"eslint-config-standard": "^17.0.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-n": "^15.3.0",
|
||||
"eslint-plugin-promise": "^6.1.0",
|
||||
"rollup": "^2.56.3",
|
||||
"rollup-plugin-terser": "^7.0.2"
|
||||
}
|
||||
}
|
||||
51
readme.md
Normal file
51
readme.md
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
 [](https://forge-vtt.com/bazaar#package=token-action-hud-template)
|
||||
|
||||
# Token Action HUD Template
|
||||
|
||||
Token Action HUD is a repositionable HUD of actions for a selected token.
|
||||
|
||||

|
||||
|
||||
# Features
|
||||
- Make rolls directly from the HUD instead of opening your character sheet.
|
||||
- Use items from the HUD or right-click an item to open its sheet.
|
||||
- Move the HUD and choose to expand the menus up or down.
|
||||
- Unlock the HUD to customise layout and groups per user, and actions per actor.
|
||||
- Add your own macros, journal entries and roll table compendiums.
|
||||
|
||||
# Installation
|
||||
|
||||
## Method 1
|
||||
1. On Foundry VTT's **Configuration and Setup** screen, go to **Add-on Modules**
|
||||
2. Click **Install Module**
|
||||
3. Search for **Token Action HUD Pathfinder 2**
|
||||
4. Click **Install** next to the module listing
|
||||
|
||||
## Method 2
|
||||
1. On Foundry VTT's **Configuration and Setup** screen, go to **Add-on Modules**
|
||||
2. Click **Install Module**
|
||||
3. In the Manifest URL field, paste: `https://github.com/Larkinabout/fvtt-token-action-hud-template/releases/latest/download/module.json`
|
||||
4. Click **Install** next to the pasted Manifest URL
|
||||
|
||||
## Required Modules
|
||||
|
||||
**IMPORTANT** - Token Action HUD Template requires the [Token Action HUD Core](https://foundryvtt.com/packages/token-action-hud-core) module to be installed.
|
||||
|
||||
## Recommended Modules
|
||||
Token Action HUD uses the [Color Picker](https://foundryvtt.com/packages/color-picker) library module for its color picker settings.
|
||||
|
||||
# Support
|
||||
|
||||
For a guide on using Token Action HUD, go to: [How to Use Token Action HUD](https://github.com/Larkinabout/fvtt-token-action-hud-core/wiki/How-to-Use-Token-Action-HUD)
|
||||
|
||||
For questions, feature requests or bug reports, please open an issue [here](https://github.com/Larkinabout/fvtt-token-action-hud-core/issues).
|
||||
|
||||
Pull requests are welcome. Please include a reason for the request or create an issue before starting one.
|
||||
|
||||
# Acknowledgements
|
||||
|
||||
Thank you to the Community Helpers on Foundry's Discord who provide tireless support for people seeking help with the HUD.
|
||||
|
||||
# License
|
||||
|
||||
This Foundry VTT module is licensed under a [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/) and this work is licensed under [Foundry Virtual Tabletop EULA - Limited License Agreement for module development](https://foundryvtt.com/article/license/).
|
||||
23
rollup.config.js
Normal file
23
rollup.config.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { terser } from 'rollup-plugin-terser'
|
||||
import multi from '@rollup/plugin-multi-entry'
|
||||
|
||||
export default [
|
||||
{
|
||||
input: {
|
||||
include: [
|
||||
'scripts/*.js',
|
||||
'scripts/*/*.js'
|
||||
],
|
||||
exclude: [
|
||||
'scripts/token-action-hud-template.min.js']
|
||||
},
|
||||
output: {
|
||||
format: 'esm',
|
||||
file: 'scripts/token-action-hud-template.min.js'
|
||||
},
|
||||
plugins: [
|
||||
terser({ keep_classnames: true, keep_fnames: true }),
|
||||
multi()
|
||||
]
|
||||
}
|
||||
]
|
||||
105
scripts/action-handler.js
Normal file
105
scripts/action-handler.js
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// System Module Imports
|
||||
import { ACTION_TYPE, ITEM_TYPE } from './constants.js'
|
||||
import { Utils } from './utils.js'
|
||||
|
||||
export let ActionHandler = null
|
||||
|
||||
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
/**
|
||||
* Extends Token Action HUD Core's ActionHandler class and builds system-defined actions for the HUD
|
||||
*/
|
||||
ActionHandler = class ActionHandler extends coreModule.api.ActionHandler {
|
||||
/**
|
||||
* Build system actions
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @param {array} groupIds
|
||||
*/a
|
||||
async buildSystemActions (groupIds) {
|
||||
// Set actor and token variables
|
||||
this.actors = (!this.actor) ? this._getActors() : [this.actor]
|
||||
this.actorType = this.actor?.type
|
||||
|
||||
// Settings
|
||||
this.displayUnequipped = Utils.getSetting('displayUnequipped')
|
||||
|
||||
// Set items variable
|
||||
if (this.actor) {
|
||||
let items = this.actor.items
|
||||
items = coreModule.api.Utils.sortItemsByName(items)
|
||||
this.items = items
|
||||
}
|
||||
|
||||
if (this.actorType === 'character') {
|
||||
this.#buildCharacterActions()
|
||||
} else if (!this.actor) {
|
||||
this.#buildMultipleTokenActions()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build character actions
|
||||
* @private
|
||||
*/
|
||||
#buildCharacterActions () {
|
||||
this.#buildInventory()
|
||||
}
|
||||
|
||||
/**
|
||||
* Build multiple token actions
|
||||
* @private
|
||||
* @returns {object}
|
||||
*/
|
||||
#buildMultipleTokenActions () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build inventory
|
||||
* @private
|
||||
*/
|
||||
async #buildInventory () {
|
||||
if (this.items.size === 0) return
|
||||
|
||||
const actionTypeId = 'item'
|
||||
const inventoryMap = new Map()
|
||||
|
||||
for (const [itemId, itemData] of this.items) {
|
||||
const type = itemData.type
|
||||
const equipped = itemData.equipped
|
||||
|
||||
if (equipped || this.displayUnequipped) {
|
||||
const typeMap = inventoryMap.get(type) ?? new Map()
|
||||
typeMap.set(itemId, itemData)
|
||||
inventoryMap.set(type, typeMap)
|
||||
}
|
||||
}
|
||||
|
||||
for (const [type, typeMap] of inventoryMap) {
|
||||
const groupId = ITEM_TYPE[type]?.groupId
|
||||
|
||||
if (!groupId) continue
|
||||
|
||||
const groupData = { id: groupId, type: 'system' }
|
||||
|
||||
// Get actions
|
||||
const actions = [...typeMap].map(([itemId, itemData]) => {
|
||||
const id = itemId
|
||||
const name = itemData.name
|
||||
const actionTypeName = coreModule.api.Utils.i18n(ACTION_TYPE[actionTypeId])
|
||||
const listName = `${actionTypeName ? `${actionTypeName}: ` : ''}${name}`
|
||||
const encodedValue = [actionTypeId, id].join(this.delimiter)
|
||||
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
listName,
|
||||
encodedValue
|
||||
}
|
||||
})
|
||||
|
||||
// TAH Core method to add actions to the action list
|
||||
this.addActions(actions, groupData)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
53
scripts/constants.js
Normal file
53
scripts/constants.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* Module-based constants
|
||||
*/
|
||||
export const MODULE = {
|
||||
ID: 'token-action-hud-template'
|
||||
}
|
||||
|
||||
/**
|
||||
* Core module
|
||||
*/
|
||||
export const CORE_MODULE = {
|
||||
ID: 'token-action-hud-core'
|
||||
}
|
||||
|
||||
/**
|
||||
* Core module version required by the system module
|
||||
*/
|
||||
export const REQUIRED_CORE_MODULE_VERSION = '1.5'
|
||||
|
||||
/**
|
||||
* Action types
|
||||
*/
|
||||
export const ACTION_TYPE = {
|
||||
item: 'tokenActionHud.template.item',
|
||||
utility: 'tokenActionHud.utility'
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups
|
||||
*/
|
||||
export const GROUP = {
|
||||
armor: { id: 'armor', name: 'tokenActionHud.template.armor', type: 'system' },
|
||||
equipment: { id: 'equipment', name: 'tokenActionHud.template.equipment', type: 'system' },
|
||||
consumables: { id: 'consumables', name: 'tokenActionHud.template.consumables', type: 'system' },
|
||||
containers: { id: 'containers', name: 'tokenActionHud.template.containers', type: 'system' },
|
||||
treasure: { id: 'treasure', name: 'tokenActionHud.template.treasure', type: 'system' },
|
||||
weapons: { id: 'weapons', name: 'tokenActionHud.template.weapons', type: 'system' },
|
||||
combat: { id: 'combat', name: 'tokenActionHud.combat', type: 'system' },
|
||||
token: { id: 'token', name: 'tokenActionHud.token', type: 'system' },
|
||||
utility: { id: 'utility', name: 'tokenActionHud.utility', type: 'system' }
|
||||
}
|
||||
|
||||
/**
|
||||
* Item types
|
||||
*/
|
||||
export const ITEM_TYPE = {
|
||||
armor: { groupId: 'armor' },
|
||||
backpack: { groupId: 'containers' },
|
||||
consumable: { groupId: 'consumables' },
|
||||
equipment: { groupId: 'equipment' },
|
||||
treasure: { groupId: 'treasure' },
|
||||
weapon: { groupId: 'weapons' }
|
||||
}
|
||||
44
scripts/defaults.js
Normal file
44
scripts/defaults.js
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { GROUP } from './constants.js'
|
||||
|
||||
/**
|
||||
* Default layout and groups
|
||||
*/
|
||||
export let DEFAULTS = null
|
||||
|
||||
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
const groups = GROUP
|
||||
Object.values(groups).forEach(group => {
|
||||
group.name = coreModule.api.Utils.i18n(group.name)
|
||||
group.listName = `Group: ${coreModule.api.Utils.i18n(group.listName ?? group.name)}`
|
||||
})
|
||||
const groupsArray = Object.values(groups)
|
||||
DEFAULTS = {
|
||||
layout: [
|
||||
{
|
||||
nestId: 'inventory',
|
||||
id: 'inventory',
|
||||
name: coreModule.api.Utils.i18n('Template.Inventory'),
|
||||
groups: [
|
||||
{ ...groups.weapons, nestId: 'inventory_weapons' },
|
||||
{ ...groups.armor, nestId: 'inventory_armor' },
|
||||
{ ...groups.equipment, nestId: 'inventory_equipment' },
|
||||
{ ...groups.consumables, nestId: 'inventory_consumables' },
|
||||
{ ...groups.containers, nestId: 'inventory_containers' },
|
||||
{ ...groups.treasure, nestId: 'inventory_treasure' }
|
||||
]
|
||||
},
|
||||
{
|
||||
nestId: 'utility',
|
||||
id: 'utility',
|
||||
name: coreModule.api.Utils.i18n('tokenActionHud.utility'),
|
||||
groups: [
|
||||
{ ...groups.combat, nestId: 'utility_combat' },
|
||||
{ ...groups.token, nestId: 'utility_token' },
|
||||
{ ...groups.rests, nestId: 'utility_rests' },
|
||||
{ ...groups.utility, nestId: 'utility_utility' }
|
||||
]
|
||||
}
|
||||
],
|
||||
groups: groupsArray
|
||||
}
|
||||
})
|
||||
14
scripts/init.js
Normal file
14
scripts/init.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { SystemManager } from './system-manager.js'
|
||||
import { MODULE, REQUIRED_CORE_MODULE_VERSION } from './constants.js'
|
||||
|
||||
Hooks.on('tokenActionHudCoreApiReady', async () => {
|
||||
/**
|
||||
* Return the SystemManager and requiredCoreModuleVersion to Token Action HUD Core
|
||||
*/
|
||||
const module = game.modules.get(MODULE.ID)
|
||||
module.api = {
|
||||
requiredCoreModuleVersion: REQUIRED_CORE_MODULE_VERSION,
|
||||
SystemManager
|
||||
}
|
||||
Hooks.call('tokenActionHudSystemReady', module)
|
||||
})
|
||||
108
scripts/roll-handler.js
Normal file
108
scripts/roll-handler.js
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
export let RollHandler = null
|
||||
|
||||
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
/**
|
||||
* Extends Token Action HUD Core's RollHandler class and handles action events triggered when an action is clicked
|
||||
*/
|
||||
RollHandler = class RollHandler extends coreModule.api.RollHandler {
|
||||
/**
|
||||
* Handle action click
|
||||
* Called by Token Action HUD Core when an action is left or right-clicked
|
||||
* @override
|
||||
* @param {object} event The event
|
||||
* @param {string} encodedValue The encoded value
|
||||
*/
|
||||
async handleActionClick (event, encodedValue) {
|
||||
const [actionTypeId, actionId] = encodedValue.split('|')
|
||||
|
||||
const renderable = ['item']
|
||||
|
||||
if (renderable.includes(actionTypeId) && this.isRenderItem()) {
|
||||
return this.doRenderItem(this.actor, actionId)
|
||||
}
|
||||
|
||||
const knownCharacters = ['character']
|
||||
|
||||
// If single actor is selected
|
||||
if (this.actor) {
|
||||
await this.#handleAction(event, this.actor, this.token, actionTypeId, actionId)
|
||||
return
|
||||
}
|
||||
|
||||
const controlledTokens = canvas.tokens.controlled
|
||||
.filter((token) => knownCharacters.includes(token.actor?.type))
|
||||
|
||||
// If multiple actors are selected
|
||||
for (const token of controlledTokens) {
|
||||
const actor = token.actor
|
||||
await this.#handleAction(event, actor, token, actionTypeId, actionId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle action hover
|
||||
* Called by Token Action HUD Core when an action is hovered on or off
|
||||
* @override
|
||||
* @param {object} event The event
|
||||
* @param {string} encodedValue The encoded value
|
||||
*/
|
||||
async handleActionHover (event, encodedValue) {}
|
||||
|
||||
/**
|
||||
* Handle group click
|
||||
* Called by Token Action HUD Core when a group is right-clicked while the HUD is locked
|
||||
* @override
|
||||
* @param {object} event The event
|
||||
* @param {object} group The group
|
||||
*/
|
||||
async handleGroupClick (event, group) {}
|
||||
|
||||
/**
|
||||
* Handle action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {object} token The token
|
||||
* @param {string} actionTypeId The action type id
|
||||
* @param {string} actionId The actionId
|
||||
*/
|
||||
async #handleAction (event, actor, token, actionTypeId, actionId) {
|
||||
switch (actionTypeId) {
|
||||
case 'item':
|
||||
this.#handleItemAction(event, actor, actionId)
|
||||
break
|
||||
case 'utility':
|
||||
this.#handleUtilityAction(token, actionId)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle item action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
#handleItemAction (event, actor, actionId) {
|
||||
const item = actor.items.get(actionId)
|
||||
item.toChat(event)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle utility action
|
||||
* @private
|
||||
* @param {object} token The token
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleUtilityAction (token, actionId) {
|
||||
switch (actionId) {
|
||||
case 'endTurn':
|
||||
if (game.combat?.current?.tokenId === token.id) {
|
||||
await game.combat?.nextTurn()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
21
scripts/settings.js
Normal file
21
scripts/settings.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { MODULE } from './constants.js'
|
||||
|
||||
/**
|
||||
* Register module settings
|
||||
* Called by Token Action HUD Core to register Token Action HUD system module settings
|
||||
* @param {function} coreUpdate Token Action HUD Core update function
|
||||
*/
|
||||
export function register (coreUpdate) {
|
||||
game.settings.register(MODULE.ID, 'displayUnequipped', {
|
||||
name: game.i18n.localize('tokenActionHud.template.settings.displayUnequipped.name'),
|
||||
hint: game.i18n.localize('tokenActionHud.template.settings.displayUnequipped.hint'
|
||||
),
|
||||
scope: 'client',
|
||||
config: true,
|
||||
type: Boolean,
|
||||
default: true,
|
||||
onChange: (value) => {
|
||||
coreUpdate(value)
|
||||
}
|
||||
})
|
||||
}
|
||||
92
scripts/system-manager.js
Normal file
92
scripts/system-manager.js
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
// System Module Imports
|
||||
import { ActionHandler } from './action-handler.js'
|
||||
import { RollHandler as Core } from './roll-handler.js'
|
||||
import { MODULE } from './constants.js'
|
||||
import { DEFAULTS } from './defaults.js'
|
||||
import * as systemSettings from './settings.js'
|
||||
|
||||
export let SystemManager = null
|
||||
|
||||
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
/**
|
||||
* Extends Token Action HUD Core's SystemManager class
|
||||
*/
|
||||
SystemManager = class SystemManager extends coreModule.api.SystemManager {
|
||||
/**
|
||||
* Returns an instance of the ActionHandler to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @returns {class} The ActionHandler instance
|
||||
*/
|
||||
getActionHandler () {
|
||||
return new ActionHandler()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of roll handlers to Token Action HUD Core
|
||||
* Used to populate the Roll Handler module setting choices
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @returns {object} The available roll handlers
|
||||
*/
|
||||
getAvailableRollHandlers () {
|
||||
const coreTitle = 'Core Template'
|
||||
const choices = { core: coreTitle }
|
||||
return choices
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of the RollHandler to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @param {string} rollHandlerId The roll handler ID
|
||||
* @returns {class} The RollHandler instance
|
||||
*/
|
||||
getRollHandler (rollHandlerId) {
|
||||
let rollHandler
|
||||
switch (rollHandlerId) {
|
||||
case 'core':
|
||||
default:
|
||||
rollHandler = new Core()
|
||||
break
|
||||
}
|
||||
return rollHandler
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default layout and groups to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @returns {object} The default layout and groups
|
||||
*/
|
||||
async registerDefaults () {
|
||||
return DEFAULTS
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Token Action HUD system module settings
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @param {function} coreUpdate The Token Action HUD Core update function
|
||||
*/
|
||||
registerSettings (coreUpdate) {
|
||||
systemSettings.register(coreUpdate)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns styles to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @returns {object} The TAH system styles
|
||||
*/
|
||||
registerStyles () {
|
||||
return {
|
||||
template: {
|
||||
class: 'tah-style-template-style', // The class to add to first DIV element
|
||||
file: 'tah-template-style', // The file without the css extension
|
||||
moduleId: MODULE.ID, // The module ID
|
||||
name: 'Template Style' // The name to display in the Token Action HUD Core 'Style' module setting
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
40
scripts/utils.js
Normal file
40
scripts/utils.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { MODULE } from './constants.js'
|
||||
|
||||
export let Utils = null
|
||||
|
||||
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
/**
|
||||
* Utility functions
|
||||
*/
|
||||
Utils = class Utils {
|
||||
/**
|
||||
* Get setting
|
||||
* @param {string} key The key
|
||||
* @param {string=null} defaultValue The default value
|
||||
* @returns {string} The setting value
|
||||
*/
|
||||
static getSetting (key, defaultValue = null) {
|
||||
let value = defaultValue ?? null
|
||||
try {
|
||||
value = game.settings.get(MODULE.ID, key)
|
||||
} catch {
|
||||
coreModule.api.Logger.debug(`Setting '${key}' not found`)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Set setting
|
||||
* @param {string} key The key
|
||||
* @param {string} value The value
|
||||
*/
|
||||
static async setSetting (key, value) {
|
||||
try {
|
||||
value = await game.settings.set(MODULE.ID, key, value)
|
||||
coreModule.api.Logger.debug(`Setting '${key}' set to '${value}'`)
|
||||
} catch {
|
||||
coreModule.api.Logger.debug(`Setting '${key}' not found`)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
484
styles/tah-template-style.css
Normal file
484
styles/tah-template-style.css
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
:root {
|
||||
--tah-background-color: #00000000;
|
||||
--tah-border-radius: 3px;
|
||||
--tah-gap: 5px;
|
||||
|
||||
--tah-button-background-color: #000000b3;
|
||||
--tah-button-border-color: none;
|
||||
--tah-button-box-shadow: 0 2px 0 -1px #0c0c0c, 0 0 0 1px #060606,
|
||||
0 0 5px #000000ff;
|
||||
--tah-button-disabled-text-color: var(--tah-text-secondary-color);
|
||||
--tah-button-text-color: var(--tah-text-primary-color);
|
||||
--tah-button-height: 32px;
|
||||
--tah-button-min-width: 32px;
|
||||
--tah-button-hover-box-shadow: 0 2px 0 -1px var(--tah-text-tertiary-color),
|
||||
0 0 0 1px red, 0 0 10px var(--tah-text-tertiary-color);
|
||||
--tah-button-hover-text-color: #fff;
|
||||
--tah-button-active-background-color: #3c0078bf;
|
||||
--tah-button-active-box-shadow: 0 0 0 1px #9b8dff, inset 0 0 10px #9b8dff;
|
||||
--tah-button-toggle-background-color: #000000b3;
|
||||
--tah-button-toggle-hover-background-color: #3c0078bf;
|
||||
--tah-button-toggle-hover-box-shadow: 0 0 0 1px #9b8dff, 0 0 10px #9b8dff;
|
||||
--tah-text-disabled-color: var(--tah-text-secondary-color);
|
||||
--tah-text-primary-color: #dddddd;
|
||||
--tah-text-secondary-color: #dddddd80;
|
||||
--tah-text-tertiary-color: #ff6400;
|
||||
--tah-text-hover-primary-color: var(--tah-text-primary-color);
|
||||
--tah-text-hover-secondary-color: var(--tah-text-secondary-color);
|
||||
--tah-text-hover-tertiary-color: var(--tah-text-tertiary-color);
|
||||
--tah-text-shadow: 1px 1px 1px rgb(0 0 0), 0px 1px 3px rgb(0 0 0);
|
||||
}
|
||||
|
||||
#token-action-hud {
|
||||
align-items: center;
|
||||
border-radius: var(--tah-border-radius);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: auto;
|
||||
left: 150px;
|
||||
position: fixed;
|
||||
top: 80px;
|
||||
width: auto;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#token-action-hud [class*="icon-"] {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#tah-character-name {
|
||||
color: var(--tah-text-primary-color);
|
||||
font-size: var(--font-size-16);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
text-align: left;
|
||||
text-shadow: var(--tah-text-shadow);
|
||||
top: -22px !important;
|
||||
}
|
||||
|
||||
.tah-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#token-action-hud:hover #tah-collapse-hud,
|
||||
#token-action-hud:hover > #tah-buttons {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#tah-collapse-hud,
|
||||
#tah-buttons {
|
||||
align-items: center;
|
||||
display: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
height: var(--tah-button-height);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#tah-collapse-expand {
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
left: -16px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#tah-collapse-hud,
|
||||
#tah-buttons button {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
line-height: unset;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#tah-collapse-hud:hover,
|
||||
#tah-collapse-hud:focus,
|
||||
#tah-buttons button:hover,
|
||||
#tah-buttons button:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#tah-collapse-expand button > :is(.fa, .fas),
|
||||
#tah-buttons button > :is(.fa, .fas) {
|
||||
color: var(--tah-text-primary-color);
|
||||
font-size: var(--font-size-12);
|
||||
margin: 3px;
|
||||
padding: 3px;
|
||||
pointer-events: none;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
text-shadow: var(--tah-text-shadow);
|
||||
}
|
||||
|
||||
#tah-collapse-expand button > :is(.fa, .fas) {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
#tah-collapse-hud {
|
||||
left: -3px;
|
||||
}
|
||||
|
||||
#tah-expand-hud {
|
||||
left: -3px;
|
||||
top: 16px;
|
||||
}
|
||||
|
||||
#tah-expand-hud,
|
||||
#tah-expand-hud:focus,
|
||||
.tah-action-button,
|
||||
.tah-action-button:focus,
|
||||
.tah-group-button,
|
||||
.tah-group-button:focus {
|
||||
align-items: center;
|
||||
background-color: var(--tah-button-background-color);
|
||||
border: var(--tah-button-border-color);
|
||||
border-radius: var(--tah-border-radius);
|
||||
box-shadow: var(--tah-button-box-shadow);
|
||||
color: var(--tah-button-text-color);
|
||||
display: flex;
|
||||
height: var(--tah-button-height);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
text-shadow: var(--tah-text-shadow);
|
||||
transition: all 0.1s ease-in-out;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.tah-action-button,
|
||||
.tah-group-button {
|
||||
font-size: var(--font-size-13);
|
||||
min-width: var(--tah-button-min-width);
|
||||
}
|
||||
|
||||
#tah-expand-hud:hover,
|
||||
.tah-action-button:active,
|
||||
.tah-action-button:not(.disabled):hover,
|
||||
.tah-group-button:not(.disabled):hover {
|
||||
box-shadow: var(--tah-button-hover-box-shadow);
|
||||
color: var(--tah-button-hover-text-color);
|
||||
}
|
||||
|
||||
.tah-action-button.toggle:not(.disabled):hover {
|
||||
background: var(--tah-button-toggle-hover-background-color);
|
||||
box-shadow: var(--tah-button-toggle-hover-box-shadow);
|
||||
}
|
||||
|
||||
.tah-action-button.active {
|
||||
background: var(--tah-button-active-background-color);
|
||||
box-shadow: var(--tah-button-active-box-shadow);
|
||||
}
|
||||
|
||||
.tah-action-button.active.activeText > .tah-action-button-content:after {
|
||||
content: "*";
|
||||
}
|
||||
|
||||
.tah-action-button.disabled {
|
||||
color: var(--tah-button-disabled-text-color);
|
||||
}
|
||||
|
||||
.tah-action-button.disabled:hover {
|
||||
box-shadow: var(--tah-button-box-shadow);
|
||||
}
|
||||
|
||||
.tah-action-button.shrink {
|
||||
min-width: min-content;
|
||||
}
|
||||
|
||||
.tah-group-button > :is(.fa, .fas) {
|
||||
font-size: 8px;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 2px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.tah-group-button:hover:not(.disable-edit)
|
||||
> :is(.fa, .fas) {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.tah-button-content:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tah-button-content {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: var(--tah-gap);
|
||||
overflow: hidden;
|
||||
padding: 0 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tah-button-text {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tah-action-button-content {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: var(--tah-gap);
|
||||
overflow: hidden;
|
||||
padding: 0 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tah-action-button-text {
|
||||
overflow: hidden;
|
||||
padding-right: 1px;
|
||||
text-align: left;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#tah-collapse-expand:hover button > i,
|
||||
#tah-buttons button:hover > i {
|
||||
color: var(--tah-text-hover-primary-color);
|
||||
text-shadow: 0 0 8px var(--color-shadow-primary);
|
||||
}
|
||||
|
||||
#tah-edit-hud > :is(.fa, .fas) {
|
||||
font-size: var(--font-size-16);
|
||||
}
|
||||
|
||||
#tah-groups,
|
||||
.tah-tab-groups {
|
||||
display: flex;
|
||||
gap: var(--tah-gap);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tah-tab-groups {
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.tah-tab-group,
|
||||
.tah-group {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tah-groups-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.tah-tab-group.hover > .tah-groups-container,
|
||||
.tah-tab-group.hover > .tah-groups-container > .tah-groups {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tah-tab-group > .tah-groups-container.expand-down > .tah-groups {
|
||||
flex-direction: column;
|
||||
left: -10px;
|
||||
padding: 3px 10px 10px 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tah-tab-group > .tah-groups-container.expand-up > .tah-groups {
|
||||
flex-direction: column;
|
||||
left: -10px;
|
||||
padding: 10px 10px 3px 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#tah-groups > .tah-tab-group > .tah-groups-container.expand-up > .tah-groups {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
.tah-tab-group > .tah-groups-container.expand-down {
|
||||
top: calc(100% - 7px);
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.tah-tab-group > .tah-groups-container.expand-up {
|
||||
bottom: calc(100% + 3px + -10px);
|
||||
flex-direction: column-reverse;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.tah-tab-group
|
||||
> .tah-groups-container.expand-up
|
||||
> .tah-groups
|
||||
> .tah-list-groups {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
.tah-list-groups,
|
||||
.tah-tab-groups > .tah-tab-group > .tah-groups > .tah-actions {
|
||||
background: var(--tah-background-color);
|
||||
border-radius: var(--tah-border-radius);
|
||||
}
|
||||
|
||||
.tah-list-groups {
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
gap: var(--tah-gap);
|
||||
}
|
||||
|
||||
.tah-list-groups .tah-list-groups {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.tah-list-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.tah-groups {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--tah-gap);
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.tah-groups.expand-down {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#tah-groups.tah-unlocked
|
||||
.tah-group
|
||||
> .tah-groups
|
||||
> .tah-list-groups
|
||||
> .tah-group {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.tah-group[data-show-title="false"]
|
||||
> .tah-list-group
|
||||
> .tah-groups
|
||||
> .tah-list-groups
|
||||
> .tah-group:not([data-show-title="false"]) {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.tah-group:not([data-show-title="false"])[data-has-image="false"]
|
||||
> .tah-list-group
|
||||
> .tah-groups
|
||||
> .tah-list-groups
|
||||
> .tah-group:not([data-show-title="false"])[data-has-image="false"] {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.tah-unlocked
|
||||
.tah-group
|
||||
> .tah-list-group
|
||||
> .tah-groups
|
||||
> .tah-list-groups
|
||||
> .tah-group {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.tah-subtitle {
|
||||
align-items: center;
|
||||
color: var(--tah-text-primary-color);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
font-size: var(--tah-font-size-10);
|
||||
gap: var(--tah-gap);
|
||||
letter-spacing: 0.1em;
|
||||
line-height: 1;
|
||||
text-shadow: var(--tah-text-shadow);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.tah-subtitle:hover {
|
||||
color: var(--tah-text-hover-primary-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tah-subtitle-text {
|
||||
color: var(--tah-text-primary-color);
|
||||
}
|
||||
|
||||
.tah-group[data-show-title="false"] > div > .tah-subtitle > .tah-subtitle-text {
|
||||
color: var(--tah-text-disabled-color);
|
||||
}
|
||||
|
||||
.tah-subtitle > :is(.tah-edit-icon, .tah-collapse-icon, .tah-expand-icon) {
|
||||
bottom: 1px;
|
||||
font-size: 8px;
|
||||
pointer-events: none;
|
||||
position: relative;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.tah-subtitle:hover
|
||||
> :is(
|
||||
.tah-collapse-icon:not(.tah-hidden),
|
||||
.tah-expand-icon:not(.tah-hidden)
|
||||
),
|
||||
.tah-subtitle:hover:not(.disable-edit) > .tah-edit-icon {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.tah-tab-group > .tah-actions {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.tah-actions {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
gap: var(--tah-gap);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tah-info1,
|
||||
.tah-info2,
|
||||
.tah-info3 {
|
||||
color: var(--tah-text-secondary-color);
|
||||
font-size: xx-small;
|
||||
}
|
||||
|
||||
.tah-info1.tah-spotlight,
|
||||
.tah-info2.tah-spotlight,
|
||||
.tah-info3.tah-spotlight {
|
||||
color: var(--tah-text-tertiary-color);
|
||||
}
|
||||
|
||||
.tah-subtitle > :is(.tah-info1, .tah-info2, .tah-info3) {
|
||||
background: var(--tah-button-background-color);
|
||||
border-radius: 5px;
|
||||
margin: 1px;
|
||||
padding: 1px 3px;
|
||||
}
|
||||
|
||||
.tah-button-image {
|
||||
border-radius: var(--tah-border-radius);
|
||||
height: var(--tah-button-height);
|
||||
min-width: var(--tah-button-min-width);
|
||||
width: var(--tah-button-min-width);
|
||||
}
|
||||
|
||||
.tah-list-image {
|
||||
border: none;
|
||||
border-radius: var(--tah-border-radius);
|
||||
box-shadow: var(--tah-button-box-shadow);
|
||||
height: var(--tah-button-height);
|
||||
margin-right: 5px;
|
||||
min-width: var(--tah-button-min-width);
|
||||
width: var(--tah-button-min-width);
|
||||
}
|
||||
|
||||
.tah-icon > :is(.fa, .fas) {
|
||||
font-size: x-small;
|
||||
margin: 0px 2px 0px 0px;
|
||||
}
|
||||
|
||||
.tah-icon-disabled {
|
||||
color: var(--tah-text-disabled-color);
|
||||
}
|
||||
|
||||
.tah-subtitle > .tah-icon > :is(.fa, .fas) {
|
||||
text-shadow: var(--tah-text-shadow);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue