feat: Default icon is now a CLI HugeIcon instead of a smiley face
This commit is contained in:
parent
19797c0784
commit
82f749a9ce
|
|
@ -39,6 +39,23 @@ And you should get something that looks like this;
|
|||
|
||||
image::../action-button-iconify.png[]
|
||||
|
||||
== HugeIcons icons (bundled)
|
||||
|
||||
The OliveTin web UI ships with curated https://www.hugeicons.com/[HugeIcons] symbols.
|
||||
Set `icon:` to `hugeicons:` followed by the icon export name, for example `hugeicons:NeutralIcon`.
|
||||
|
||||
This is the neutral glyph OliveTin uses when no icon is configured for an action.
|
||||
|
||||
.`config.yaml`
|
||||
----
|
||||
actions:
|
||||
- title: Action with the bundled CLI HugeIcon
|
||||
icon: hugeicons:CommandLineIcon
|
||||
shell: echo hello
|
||||
----
|
||||
|
||||
Known `hugeicons:` names are registered in the web UI (`ActionIconGlyph` Vue component).
|
||||
|
||||
== Unicode icons ("emoji")
|
||||
|
||||
Using simple emoji (unicode) icons from your browser's font is extremely fast, and can look good on some platforms. However, the icons are platform specific, which mean's they'll look different between browsers and between operating systems.
|
||||
|
|
@ -140,5 +157,3 @@ examples;
|
|||
shell: echo "I like purple"
|
||||
----
|
||||
////
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ All configuration options are covered in the solution sections
|
|||
| `showNavigateOnStartIcons` | Show (or hide) the small icons on action buttons that indicate popup/argument/background behavior on start. | `true` | Live reloadable | xref:advanced_configuration/webui.adoc[Customize the web UI].
|
||||
| `sectionNavigationStyle` | The style of the section navigation. `sidebar`, `topbar` | `sidebar` | Live reloadable | xref:advanced_configuration/webui.adoc[Customize the web UI].
|
||||
| `defaultPopupOnStart` | The default popup to show on start. | `none` | Live reloadable | xref:action_customization/popuponstart.adoc[Popup On Start].
|
||||
| `defaultIconForActions` | The default icon to use for actions. | `smile` | Requires Restart | -
|
||||
| `defaultIconForActions` | The default icon string for actions (Unicode aliases such as `smile`, `hugeicons:NeutralIcon`, HTML, Iconify snippets, images, etc.). See xref:action_customization/icons.adoc[Icons]. | `hugeicons:CommandLineIcon` | Requires Restart | -
|
||||
| `defaultIconForDirectories` | The default icon to use for directories. | `directory` | Requires Restart | -
|
||||
| `defaultIconForBack` | The default icon to use for back (from directories). | `«` | Requires Restart | -
|
||||
| `enableCustomJs` | Enable custom JavaScript. | `false` | Live Reloadable, but refreshing the web browser is required. | xref:advanced_configuration/webui.adoc[Custom JS].
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<span class="icon" v-html="unicodeIcon"></span>
|
||||
<ActionIconGlyph class="icon" :glyph="actionGlyph" />
|
||||
<span class="title" aria-live="polite">{{ displayTitle }}
|
||||
</span>
|
||||
<span v-if="rateLimitMessage" class="rate-limit-message">{{ rateLimitMessage }}</span>
|
||||
|
|
@ -30,7 +30,9 @@ import { useRouter } from 'vue-router'
|
|||
import { HugeiconsIcon } from '@hugeicons/vue'
|
||||
import { WorkoutRunIcon, TypeCursorIcon, ComputerTerminal01Icon } from '@hugeicons/core-free-icons'
|
||||
|
||||
import { ref, watch, onMounted, onUnmounted, inject, computed } from 'vue'
|
||||
import ActionIconGlyph from './components/ActionIconGlyph.vue'
|
||||
|
||||
import { ref, watch, onMounted, onUnmounted, computed } from 'vue'
|
||||
|
||||
const router = useRouter()
|
||||
const navigateOnStart = ref('')
|
||||
|
|
@ -53,7 +55,6 @@ const canExec = ref(true)
|
|||
const popupOnStart = ref('')
|
||||
|
||||
// Display properties
|
||||
const unicodeIcon = ref('💩')
|
||||
const displayTitle = ref('')
|
||||
|
||||
// State
|
||||
|
|
@ -74,6 +75,8 @@ const showNavigateOnStartIcons = computed(() => {
|
|||
return window.initResponse?.showNavigateOnStartIcons ?? true
|
||||
})
|
||||
|
||||
const actionGlyph = computed(() => props.actionData?.icon ?? '')
|
||||
|
||||
// Combined classes including custom cssClass
|
||||
const combinedClasses = computed(() => {
|
||||
const classes = [...buttonClasses.value]
|
||||
|
|
@ -86,16 +89,6 @@ const combinedClasses = computed(() => {
|
|||
// Timestamps
|
||||
const updateIterationTimestamp = ref(0)
|
||||
|
||||
function getUnicodeIcon(icon) {
|
||||
if (icon === '') {
|
||||
console.log('icon not found ', icon)
|
||||
|
||||
return '💩'
|
||||
} else {
|
||||
return unescape(icon)
|
||||
}
|
||||
}
|
||||
|
||||
function constructFromJson(json) {
|
||||
updateIterationTimestamp.value = 0
|
||||
|
||||
|
|
@ -114,8 +107,6 @@ function constructFromJson(json) {
|
|||
|
||||
isDisabled.value = !json.canExec
|
||||
displayTitle.value = title.value
|
||||
unicodeIcon.value = getUnicodeIcon(json.icon)
|
||||
|
||||
// Initialize rate limit from action data (parse datetime string)
|
||||
if (json.datetimeRateLimitExpires) {
|
||||
const date = new Date(json.datetimeRateLimitExpires.replace(' ', 'T'))
|
||||
|
|
@ -134,8 +125,6 @@ function updateFromJson(json) {
|
|||
// Fields that should not be updated
|
||||
// title - as the callback URL relies on it
|
||||
|
||||
unicodeIcon.value = getUnicodeIcon(json.icon)
|
||||
|
||||
// Update rate limiting if changed (parse datetime string)
|
||||
if (json.datetimeRateLimitExpires) {
|
||||
const date = new Date(json.datetimeRateLimitExpires.replace(' ', 'T'))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
<template>
|
||||
<span class="action-icon-glyph">
|
||||
<HugeiconsIcon
|
||||
v-if="hugeiconsModel"
|
||||
:icon="hugeiconsModel"
|
||||
width="1em"
|
||||
height="1em"
|
||||
class="action-icon-glyph-svg"
|
||||
/>
|
||||
<span v-else v-html="decodedHtmlGlyph"></span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { HugeiconsIcon } from '@hugeicons/vue'
|
||||
import { CommandLineIcon } from '@hugeicons/core-free-icons'
|
||||
|
||||
const hugeiconsPrefix = 'hugeicons:'
|
||||
|
||||
/** Maps config values like hugeicons:CommandLineIcon to Hugeicons icon definitions. */
|
||||
const hugeiconsRegistry = {
|
||||
CommandLineIcon,
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
glyph: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const hugeiconsModel = computed(() => {
|
||||
if (!props.glyph.startsWith(hugeiconsPrefix)) {
|
||||
return null
|
||||
}
|
||||
const name = props.glyph.slice(hugeiconsPrefix.length)
|
||||
const iconModel = hugeiconsRegistry[name]
|
||||
|
||||
return iconModel ?? CommandLineIcon
|
||||
})
|
||||
|
||||
const decodedHtmlGlyph = computed(() => {
|
||||
if (props.glyph === '') {
|
||||
return '💩'
|
||||
}
|
||||
|
||||
if (hugeiconsModel.value) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return unescape(props.glyph)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.action-icon-glyph {
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.action-icon-glyph-svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
</p>
|
||||
</div>
|
||||
<div style = "align-self: start; text-align: right;">
|
||||
<span class="icon" v-html="action.icon"></span>
|
||||
<ActionIconGlyph class="icon" :glyph="action.icon" />
|
||||
|
||||
<div class="filter-container">
|
||||
<label class="input-with-icons">
|
||||
|
|
@ -94,6 +94,7 @@ import { ref, computed, onMounted, watch } from 'vue'
|
|||
import { useRoute, useRouter } from 'vue-router'
|
||||
import Pagination from 'picocrank/vue/components/Pagination.vue'
|
||||
import Section from 'picocrank/vue/components/Section.vue'
|
||||
import ActionIconGlyph from '../components/ActionIconGlyph.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
|
@ -386,4 +387,3 @@ watch(
|
|||
padding: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
<ActionStatusDisplay :log-entry="logEntry" id = "execution-dialog-status" />
|
||||
</dd>
|
||||
</dl>
|
||||
<span class="icon" role="img" v-html="icon" style = "align-self: start"></span>
|
||||
<ActionIconGlyph class="icon" role="img" :glyph="icon" style="align-self: start" />
|
||||
</div>
|
||||
|
||||
<div v-if="notFound" class="error-message padded-content">
|
||||
|
|
@ -62,6 +62,7 @@
|
|||
|
||||
<script setup>
|
||||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
|
||||
import ActionIconGlyph from '../components/ActionIconGlyph.vue'
|
||||
import ActionStatusDisplay from '../components/ActionStatusDisplay.vue'
|
||||
import Section from 'picocrank/vue/components/Section.vue'
|
||||
import { OutputTerminal } from '../../../js/OutputTerminal.js'
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
<tr v-for="log in filteredLogs" :key="log.executionTrackingId" class="log-row" :title="log.actionTitle">
|
||||
<td class="timestamp">{{ formatTimestamp(log.datetimeStarted) }}</td>
|
||||
<td>
|
||||
<span class="icon" v-html="log.actionIcon"></span>
|
||||
<ActionIconGlyph class="icon" :glyph="log.actionIcon" />
|
||||
<router-link :to="`/logs/${log.executionTrackingId}`">
|
||||
{{ log.actionTitle }}
|
||||
</router-link>
|
||||
|
|
@ -93,6 +93,7 @@ import Pagination from 'picocrank/vue/components/Pagination.vue'
|
|||
import Section from 'picocrank/vue/components/Section.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import ActionStatusDisplay from '../components/ActionStatusDisplay.vue'
|
||||
import ActionIconGlyph from '../components/ActionIconGlyph.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ func DefaultConfigWithBasePort(basePort int) *Config {
|
|||
config.Security.HeaderXContentTypeOptions = true
|
||||
config.Security.HeaderXFrameOptions = true
|
||||
config.Security.XFrameOptions = "DENY"
|
||||
config.DefaultIconForActions = "😀"
|
||||
config.DefaultIconForActions = "hugeicons:CommandLineIcon"
|
||||
config.DefaultIconForDirectories = "📁"
|
||||
config.DefaultIconForBack = "«"
|
||||
config.ThemeCacheDisabled = false
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func TestSanitizeConfig(t *testing.T) {
|
|||
|
||||
assert.NotNil(t, a2, "Found action after adding it")
|
||||
assert.Equal(t, 3, a2.Timeout, "Default timeout is set")
|
||||
assert.Equal(t, "😀", a2.Icon, "Default icon is a smiley")
|
||||
assert.Equal(t, "hugeicons:CommandLineIcon", a2.Icon, "Default icon is the neutral CLI glyph")
|
||||
assert.Equal(t, "Carrots", a2.Arguments[0].Title, "Arg title is set to name")
|
||||
assert.Equal(t, "Waffle", a2.Arguments[0].Choices[0].Title, "Choice title is set to name")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue