refactor(ui): getting ride of naive ui buttons

This commit is contained in:
Corentin Thomasset 2023-04-19 21:38:59 +02:00 committed by Corentin THOMASSET
parent df989e24b3
commit c45bce36f9
44 changed files with 738 additions and 204 deletions

72
components.d.ts vendored
View File

@ -9,13 +9,62 @@ export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
'404.page': typeof import('./src/pages/404.page.vue')['default']
About: typeof import('./src/pages/About.vue')['default']
App: typeof import('./src/App.vue')['default']
'Base.layout': typeof import('./src/layouts/base.layout.vue')['default']
Base64FileConverter: typeof import('./src/tools/base64-file-converter/base64-file-converter.vue')['default']
Base64StringConverter: typeof import('./src/tools/base64-string-converter/base64-string-converter.vue')['default']
BasicAuthGenerator: typeof import('./src/tools/basic-auth-generator/basic-auth-generator.vue')['default']
Bcrypt: typeof import('./src/tools/bcrypt/bcrypt.vue')['default']
BenchmarkBuilder: typeof import('./src/tools/benchmark-builder/benchmark-builder.vue')['default']
Bip39Generator: typeof import('./src/tools/bip39-generator/bip39-generator.vue')['default']
CaseConverter: typeof import('./src/tools/case-converter/case-converter.vue')['default']
CButton: typeof import('./src/ui/c-button/c-button.vue')['default']
ChmodCalculator: typeof import('./src/tools/chmod-calculator/chmod-calculator.vue')['default']
Chronometer: typeof import('./src/tools/chronometer/chronometer.vue')['default']
CLink: typeof import('./src/ui/c-link/c-link.vue')['default']
CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default']
ColorConverter: typeof import('./src/tools/color-converter/color-converter.vue')['default']
ColoredCard: typeof import('./src/components/ColoredCard.vue')['default']
CopyableIpLike: typeof import('./src/tools/ipv4-subnet-calculator/copyable-ip-like.vue')['default']
CrontabGenerator: typeof import('./src/tools/crontab-generator/crontab-generator.vue')['default']
DateTimeConverter: typeof import('./src/tools/date-time-converter/date-time-converter.vue')['default']
DeviceInformation: typeof import('./src/tools/device-information/device-information.vue')['default']
DockerRunToDockerComposeConverter: typeof import('./src/tools/docker-run-to-docker-compose-converter/docker-run-to-docker-compose-converter.vue')['default']
DynamicValues: typeof import('./src/tools/benchmark-builder/dynamic-values.vue')['default']
Editor: typeof import('./src/tools/html-wysiwyg-editor/editor/editor.vue')['default']
Encryption: typeof import('./src/tools/encryption/encryption.vue')['default']
EtaCalculator: typeof import('./src/tools/eta-calculator/eta-calculator.vue')['default']
FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default']
FormatTransformer: typeof import('./src/components/FormatTransformer.vue')['default']
GitMemo: typeof import('./src/tools/git-memo/git-memo.md')['default']
HashText: typeof import('./src/tools/hash-text/hash-text.vue')['default']
HmacGenerator: typeof import('./src/tools/hmac-generator/hmac-generator.vue')['default']
'Home.page': typeof import('./src/pages/Home.page.vue')['default']
HtmlEntities: typeof import('./src/tools/html-entities/html-entities.vue')['default']
HtmlWysiwygEditor: typeof import('./src/tools/html-wysiwyg-editor/html-wysiwyg-editor.vue')['default']
HttpStatusCodes: typeof import('./src/tools/http-status-codes/http-status-codes.vue')['default']
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default']
Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default']
Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default']
Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default']
Ipv6UlaGenerator: typeof import('./src/tools/ipv6-ula-generator/ipv6-ula-generator.vue')['default']
JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default']
JsonToYaml: typeof import('./src/tools/json-to-yaml-converter/json-to-yaml.vue')['default']
JsonViewer: typeof import('./src/tools/json-viewer/json-viewer.vue')['default']
JwtParser: typeof import('./src/tools/jwt-parser/jwt-parser.vue')['default']
KeycodeInfo: typeof import('./src/tools/keycode-info/keycode-info.vue')['default']
LoremIpsumGenerator: typeof import('./src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue')['default']
MacAddressLookup: typeof import('./src/tools/mac-address-lookup/mac-address-lookup.vue')['default']
MathEvaluator: typeof import('./src/tools/math-evaluator/math-evaluator.vue')['default']
MenuBar: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar.vue')['default']
MenuBarItem: typeof import('./src/tools/html-wysiwyg-editor/editor/menu-bar-item.vue')['default']
MenuIconItem: typeof import('./src/components/MenuIconItem.vue')['default']
MenuLayout: typeof import('./src/components/MenuLayout.vue')['default']
MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default']
MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default']
NAlert: typeof import('naive-ui')['NAlert']
NAutoComplete: typeof import('naive-ui')['NAutoComplete']
NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default']
@ -37,7 +86,6 @@ declare module '@vue/runtime-core' {
NH1: typeof import('naive-ui')['NH1']
NH2: typeof import('naive-ui')['NH2']
NH3: typeof import('naive-ui')['NH3']
NH4: typeof import('naive-ui')['NH4']
NIcon: typeof import('naive-ui')['NIcon']
NImage: typeof import('naive-ui')['NImage']
NInput: typeof import('naive-ui')['NInput']
@ -50,7 +98,6 @@ declare module '@vue/runtime-core' {
NP: typeof import('naive-ui')['NP']
NPageHeader: typeof import('naive-ui')['NPageHeader']
NProgress: typeof import('naive-ui')['NProgress']
NResult: typeof import('naive-ui')['NResult']
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSelect: typeof import('naive-ui')['NSelect']
NSlider: typeof import('naive-ui')['NSlider']
@ -63,12 +110,33 @@ declare module '@vue/runtime-core' {
NTooltip: typeof import('naive-ui')['NTooltip']
NUpload: typeof import('naive-ui')['NUpload']
NUploadDragger: typeof import('naive-ui')['NUploadDragger']
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
QrCodeGenerator: typeof import('./src/tools/qr-code-generator/qr-code-generator.vue')['default']
RandomPortGenerator: typeof import('./src/tools/random-port-generator/random-port-generator.vue')['default']
ResultRow: typeof import('./src/tools/ipv4-range-expander/result-row.vue')['default']
RomanNumeralConverter: typeof import('./src/tools/roman-numeral-converter/roman-numeral-converter.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default']
SearchBar: typeof import('./src/components/SearchBar.vue')['default']
SearchBarItem: typeof import('./src/components/SearchBarItem.vue')['default']
SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default']
SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default']
SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default']
SvgPlaceholderGenerator: typeof import('./src/tools/svg-placeholder-generator/svg-placeholder-generator.vue')['default']
TemperatureConverter: typeof import('./src/tools/temperature-converter/temperature-converter.vue')['default']
TextareaCopyable: typeof import('./src/components/TextareaCopyable.vue')['default']
TextStatistics: typeof import('./src/tools/text-statistics/text-statistics.vue')['default']
TextToNatoAlphabet: typeof import('./src/tools/text-to-nato-alphabet/text-to-nato-alphabet.vue')['default']
TokenDisplay: typeof import('./src/tools/otp-code-generator-and-validator/token-display.vue')['default']
'TokenGenerator.tool': typeof import('./src/tools/token-generator/token-generator.tool.vue')['default']
'Tool.layout': typeof import('./src/layouts/tool.layout.vue')['default']
ToolCard: typeof import('./src/components/ToolCard.vue')['default']
UrlEncoder: typeof import('./src/tools/url-encoder/url-encoder.vue')['default']
UrlParser: typeof import('./src/tools/url-parser/url-parser.vue')['default']
UserAgentParser: typeof import('./src/tools/user-agent-parser/user-agent-parser.vue')['default']
UserAgentResultCards: typeof import('./src/tools/user-agent-parser/user-agent-result-cards.vue')['default']
UuidGenerator: typeof import('./src/tools/uuid-generator/uuid-generator.vue')['default']
YamlToJson: typeof import('./src/tools/yaml-to-json-converter/yaml-to-json.vue')['default']
}
}

View File

@ -1,11 +1,15 @@
<template>
<n-tooltip trigger="hover">
<template #trigger>
<n-button circle quaternary :type="buttonType" :style="{ opacity: isFavorite ? 1 : 0.2 }" @click="toggleFavorite">
<template #icon>
<n-icon :component="FavoriteFilled" />
</template>
</n-button>
<c-button
variant="text"
circle
:type="buttonType"
:style="{ opacity: isFavorite ? 1 : 0.2 }"
@click="toggleFavorite"
>
<n-icon :component="FavoriteFilled" />
</c-button>
</template>
{{ isFavorite ? 'Remove from favorites' : 'Add to favorites' }}
</n-tooltip>

View File

@ -3,9 +3,9 @@
<template #suffix>
<n-tooltip trigger="hover">
<template #trigger>
<n-button quaternary circle @click="onCopyClicked">
<c-button circle variant="text" @click="onCopyClicked">
<n-icon :component="ContentCopyFilled" />
</n-button>
</c-button>
</template>
{{ tooltipText }}
</n-tooltip>

View File

@ -1,56 +1,50 @@
<template>
<n-tooltip trigger="hover">
<template #trigger>
<n-button
size="large"
<c-button
circle
quaternary
tag="a"
variant="text"
href="https://github.com/CorentinTh/it-tools"
rel="noopener"
target="_blank"
rel="noopener noreferrer"
aria-label="IT-Tools' GitHub repository"
>
<n-icon size="25" :component="BrandGithub" />
</n-button>
</c-button>
</template>
Github repository
</n-tooltip>
<n-tooltip trigger="hover">
<template #trigger>
<n-button
size="large"
<c-button
circle
quaternary
tag="a"
variant="text"
href="https://twitter.com/ittoolsdottech"
rel="noopener"
target="_blank"
aria-label="IT Tools' Twitter account"
>
<n-icon size="25" :component="BrandTwitter" />
</n-button>
</c-button>
</template>
IT Tools' Twitter account
</n-tooltip>
<router-link to="/about" #="{ navigate, href }" custom>
<n-tooltip trigger="hover">
<template #trigger>
<n-button tag="a" :href="href" circle quaternary size="large" aria-label="About" @click="navigate">
<n-icon size="25" :component="InfoCircle" />
</n-button>
</template>
About
</n-tooltip>
</router-link>
<n-tooltip trigger="hover">
<template #trigger>
<n-button size="large" circle quaternary aria-label="Toggle dark/light mode" @click="isDarkTheme = !isDarkTheme">
<c-button circle variant="text" to="/about" aria-label="About">
<n-icon size="25" :component="InfoCircle" />
</c-button>
</template>
About
</n-tooltip>
<n-tooltip trigger="hover">
<template #trigger>
<c-button circle variant="text" aria-label="Toggle dark/light mode" @click="toggleDarkTheme">
<n-icon v-if="isDarkTheme" size="25" :component="Sun" />
<n-icon v-else size="25" :component="Moon" />
</n-button>
</c-button>
</template>
<span v-if="isDarkTheme">Light mode</span>
<span v-else>Dark mode</span>
@ -59,11 +53,20 @@
<script setup lang="ts">
import { useStyleStore } from '@/stores/style.store';
import { useThemeStore } from '@/ui/theme/theme.store';
import { BrandGithub, BrandTwitter, InfoCircle, Moon, Sun } from '@vicons/tabler';
import { toRefs } from 'vue';
const styleStore = useStyleStore();
const { isDarkTheme } = toRefs(styleStore);
const themeStore = useThemeStore();
function toggleDarkTheme() {
isDarkTheme.value = !isDarkTheme.value;
themeStore.toggleTheme();
}
</script>
<style lang="less" scoped>

View File

@ -13,16 +13,16 @@
<n-tooltip v-if="value" trigger="hover">
<template #trigger>
<div class="copy-button" :class="[copyPlacement]">
<n-button circle secondary size="large" @click="onCopyClicked">
<c-button circle important:h-10 important:w-10 @click="onCopyClicked">
<n-icon size="22" :component="Copy" />
</n-button>
</c-button>
</div>
</template>
<span>{{ tooltipText }}</span>
</n-tooltip>
</n-card>
<n-space v-if="copyPlacement === 'outside'" justify="center" mt-4>
<n-button secondary @click="onCopyClicked"> {{ tooltipText }} </n-button>
<c-button @click="onCopyClicked"> {{ tooltipText }} </c-button>
</n-space>
</div>
</template>

View File

@ -53,38 +53,25 @@ const tools = computed<ToolCategory[]>(() => [
<div>
IT-Tools
<n-button
text
tag="a"
target="_blank"
rel="noopener"
type="primary"
depth="3"
:href="`https://github.com/CorentinTh/it-tools/tree/v${version}`"
>
<c-link target="_blank" rel="noopener" :href="`https://github.com/CorentinTh/it-tools/tree/v${version}`">
v{{ version }}
</n-button>
</c-link>
<template v-if="commitSha && commitSha.length > 0">
-
<n-button
text
tag="a"
<c-link
target="_blank"
rel="noopener"
type="primary"
depth="3"
:href="`https://github.com/CorentinTh/it-tools/tree/${commitSha}`"
>
{{ commitSha }}
</n-button>
</c-link>
</template>
</div>
<div>
© {{ new Date().getFullYear() }}
<n-button text tag="a" target="_blank" rel="noopener" type="primary" href="https://github.com/CorentinTh">
Corentin Thomasset
</n-button>
<c-link target="_blank" rel="noopener" href="https://github.com/CorentinTh"> Corentin Thomasset </c-link>
</div>
</div>
</div>
@ -92,34 +79,24 @@ const tools = computed<ToolCategory[]>(() => [
<template #content>
<div class="navigation">
<n-button
<c-button
:size="styleStore.isSmallScreen ? 'medium' : 'large'"
circle
quaternary
variant="text"
aria-label="Toggle menu"
@click="styleStore.isMenuCollapsed = !styleStore.isMenuCollapsed"
>
<n-icon size="25" :component="Menu2" />
</n-button>
</c-button>
<router-link to="/" #="{ navigate, href }" custom>
<n-tooltip trigger="hover">
<template #trigger>
<n-button
tag="a"
:href="href"
:size="styleStore.isSmallScreen ? 'medium' : 'large'"
circle
quaternary
aria-label="Home"
@click="navigate"
>
<n-icon size="25" :component="Home2" />
</n-button>
</template>
Home
</n-tooltip>
</router-link>
<n-tooltip trigger="hover">
<template #trigger>
<c-button to="/" circle variant="text" aria-label="Home">
<n-icon size="25" :component="Home2" />
</c-button>
</template>
Home
</n-tooltip>
<search-bar />
@ -127,10 +104,8 @@ const tools = computed<ToolCategory[]>(() => [
<n-tooltip trigger="hover">
<template #trigger>
<n-button
<c-button
round
type="primary"
tag="a"
href="https://www.buymeacoffee.com/cthmsst"
rel="noopener"
target="_blank"
@ -140,7 +115,7 @@ const tools = computed<ToolCategory[]>(() => [
>
Buy me a coffee
<n-icon v-if="!styleStore.isSmallScreen" :component="Heart" ml-2 />
</n-button>
</c-button>
</template>
Support IT Tools development !
</n-tooltip>
@ -165,8 +140,8 @@ const tools = computed<ToolCategory[]>(() => [
.support-button {
background: rgb(37, 99, 108);
background: linear-gradient(48deg, rgba(37, 99, 108, 1) 0%, rgba(59, 149, 111, 1) 60%, rgba(20, 160, 88, 1) 100%);
color: #fff;
transition: all ease 0.2s;
color: #fff !important;
transition: padding ease 0.2s !important;
&:hover {
color: #fff;

View File

@ -13,8 +13,6 @@ useHead({ title: 'Page not found - IT Tools' });
<n-text mt-4 block depth="3">Sorry, this page does not seem to exist</n-text>
<n-text mb-8 block depth="3">Maybe the cache is doing tricky things, try force-refreshing?</n-text>
<router-link to="/" #="{ navigate, href }" custom>
<n-button tag="a" :href="href" secondary @click="navigate"> Back home </n-button>
</router-link>
<c-button to="/"> Back home </c-button>
</div>
</template>

View File

@ -11,25 +11,21 @@ const { tracker } = useTracker();
<n-h1>About</n-h1>
<n-p>
This wonderful website, made with by
<n-button text tag="a" href="https://github.com/CorentinTh" target="_blank" rel="noopener" type="primary">
Corentin Thomasset </n-button
>, aggregates useful tools for developer and people working in IT. If you find it useful, please fell free to
share it to people you think may find it useful too and don't forget to pin it in your shortcut bar !
<c-link href="https://github.com/CorentinTh" target="_blank" rel="noopener"> Corentin Thomasset </c-link>,
aggregates useful tools for developer and people working in IT. If you find it useful, please fell free to share
it to people you think may find it useful too and don't forget to pin it in your shortcut bar !
</n-p>
<n-p>
IT Tools is open-source (under the MIT license) and free, and will always be, but it cost me money to host and
renew the domain name, if you want to support my work, and encourage me to add more tools, please consider
supporting by
<n-button
type="primary"
tag="a"
text
<c-link
href="https://www.buymeacoffee.com/cthmsst"
rel="noopener"
target="_blank"
@click="() => tracker.trackEvent({ eventName: 'Support button clicked' })"
>
sponsoring me </n-button
sponsoring me </c-link
>.
</n-p>
@ -37,16 +33,9 @@ const { tracker } = useTracker();
<n-p>
IT Tools is made in Vue JS (vue 3) with the the naive-ui component library and is hosted and continuously deployed
by Vercel. Third party open-source libraries are used in some tools, you may find the complete list in the
<n-button
type="primary"
tag="a"
text
href="https://github.com/CorentinTh/it-tools/blob/main/package.json"
rel="noopener"
target="_blank"
>
<c-link href="https://github.com/CorentinTh/it-tools/blob/main/package.json" rel="noopener" target="_blank">
package.json
</n-button>
</c-link>
file of the repository.
</n-p>
@ -54,30 +43,24 @@ const { tracker } = useTracker();
<n-p>
If you need a tool that is currently not present here, and you think can be relevant, you are welcome to submit a
feature request in the
<n-button
type="primary"
tag="a"
text
<c-link
href="https://github.com/CorentinTh/it-tools/issues/new?assignees=CorentinTh&labels=enhancement&template=feature_request.md&title=%5BFEAT%5D%20My%20feature"
rel="noopener"
target="_blank"
>
issues section
</n-button>
</c-link>
in the GitHub repository.
</n-p>
<n-p>
And if you found a bug, or something broken that doesn't work as expected, please fill a bug report in the
<n-button
type="primary"
tag="a"
text
<c-link
href="https://github.com/CorentinTh/it-tools/issues/new?assignees=CorentinTh&labels=bug&template=bug_report.md&title=%5BBUG%5D%20My%20bug"
rel="noopener"
target="_blank"
>
issues section
</n-button>
</c-link>
in the GitHub repository.
</n-p>
</div>

View File

@ -8,9 +8,9 @@
<n-input v-model:value="base64Input" type="textarea" placeholder="Put your base64 file string here..." rows="5" />
</n-form-item>
<n-space justify="center">
<n-button :disabled="base64Input === '' || !base64InputValidation.isValid" secondary @click="downloadFile()">
<c-button :disabled="base64Input === '' || !base64InputValidation.isValid" @click="downloadFile()">
Download file
</n-button>
</c-button>
</n-space>
</n-card>
@ -26,7 +26,7 @@
<n-input :value="fileBase64" type="textarea" readonly placeholder="File in base64 will be here" />
<n-space justify="center">
<n-button secondary @click="copyFileBase64()"> Copy </n-button>
<c-button @click="copyFileBase64()"> Copy </c-button>
</n-space>
</n-card>
</template>

View File

@ -15,7 +15,7 @@
</n-form-item>
<n-space justify="center">
<n-button secondary @click="copyTextBase64()"> Copy base64 </n-button>
<c-button @click="copyTextBase64()"> Copy base64 </c-button>
</n-space>
</n-card>
@ -29,7 +29,7 @@
</n-form-item>
<n-space justify="center">
<n-button secondary @click="copyText()"> Copy decoded string </n-button>
<c-button @click="copyText()"> Copy decoded string </c-button>
</n-space>
</n-card>
</template>

View File

@ -23,7 +23,7 @@
</n-card>
<br />
<n-space justify="center">
<n-button secondary @click="copy">Copy header</n-button>
<c-button @click="copy">Copy header</c-button>
</n-space>
</div>
</template>

View File

@ -18,7 +18,7 @@
</n-form>
<br />
<n-space justify="center">
<n-button secondary @click="copy"> Copy hash </n-button>
<c-button @click="copy"> Copy hash </c-button>
</n-space>
</n-card>

View File

@ -14,18 +14,17 @@
</n-card>
<n-space justify="center">
<n-button v-if="suites.length > 1" quaternary @click="suites.splice(index, 1)">
<template #icon>
<n-icon :component="Trash" depth="3" />
</template>
<c-button v-if="suites.length > 1" variant="text" @click="suites.splice(index, 1)">
<n-icon :component="Trash" depth="3" mr-2 size="18" />
Delete suite
</n-button>
<n-button quaternary @click="suites.splice(index + 1, 0, { data: [0], title: `Suite ${suites.length + 1}` })">
<template #icon>
<n-icon :component="Plus" depth="3" />
</template>
</c-button>
<c-button
variant="text"
@click="suites.splice(index + 1, 0, { data: [0], title: `Suite ${suites.length + 1}` })"
>
<n-icon :component="Plus" depth="3" mr-2 size="18" />
Add suite
</n-button>
</c-button>
</n-space>
</div>
</n-space>
@ -39,15 +38,14 @@
<n-input v-model:value="unit" placeholder="Unit (eg: ms)" />
</n-form-item>
<n-button
tertiary
<c-button
@click="
suites = [
{ title: 'Suite 1', data: [] },
{ title: 'Suite 2', data: [] },
]
"
>Reset suites</n-button
>Reset suites</c-button
>
</n-space>
@ -73,8 +71,8 @@
</n-table>
<br />
<n-space justify="center">
<n-button tertiary @click="copyAsMarkdown">Copy as markdown table</n-button>
<n-button tertiary @click="copyAsBulletList">Copy as bullet list</n-button>
<c-button @click="copyAsMarkdown">Copy as markdown table</c-button>
<c-button @click="copyAsBulletList">Copy as bullet list</c-button>
</n-space>
</div>
</div>

View File

@ -11,22 +11,18 @@
/>
<n-tooltip>
<template #trigger>
<n-button circle quaternary @click="values.splice(index, 1)">
<template #icon>
<n-icon :component="Trash" depth="3" />
</template>
</n-button>
<c-button circle variant="text" @click="values.splice(index, 1)">
<n-icon :component="Trash" depth="3" size="18" />
</c-button>
</template>
Delete value
</n-tooltip>
</n-space>
<n-button tertiary @click="addValue">
<template #icon>
<n-icon :component="Plus" />
</template>
<c-button @click="addValue">
<n-icon :component="Plus" depth="3" mr-2 size="18" />
Add a measure
</n-button>
</c-button>
</div>
</template>

View File

@ -18,16 +18,16 @@
>
<n-input-group>
<n-input v-model:value="entropy" placeholder="Your string..." />
<n-button @click="refreshEntropy">
<c-button @click="refreshEntropy">
<n-icon size="22">
<Refresh />
</n-icon>
</n-button>
<n-button @click="copyEntropy">
</c-button>
<c-button @click="copyEntropy">
<n-icon size="22">
<Copy />
</n-icon>
</n-button>
</c-button>
</n-input-group>
</n-form-item>
</n-gi>
@ -48,9 +48,9 @@
spellcheck="false"
/>
<n-button @click="copyPassphrase">
<c-button @click="copyPassphrase">
<n-icon size="22" :component="Copy" />
</n-button>
</c-button>
</n-input-group>
</n-form-item>
</n-card>

View File

@ -5,10 +5,10 @@
</n-card>
<br />
<n-space justify="center">
<n-button v-if="!isRunning" secondary type="primary" @click="resume">Start</n-button>
<n-button v-else secondary type="warning" @click="pause">Stop</n-button>
<c-button v-if="!isRunning" secondary type="primary" @click="resume">Start</c-button>
<c-button v-else secondary type="warning" @click="pause">Stop</c-button>
<n-button secondary @click="counter = 0">Reset</n-button>
<c-button @click="counter = 0">Reset</c-button>
</n-space>
</div>
</template>

View File

@ -16,7 +16,7 @@
<br />
<br />
<n-space justify="center">
<n-button :disabled="dockerCompose === ''" secondary @click="download"> Download docker-compose.yml </n-button>
<c-button :disabled="dockerCompose === ''" secondary @click="download"> Download docker-compose.yml </c-button>
</n-space>
<div v-if="notComposable.length > 0">

View File

@ -43,7 +43,7 @@
<n-input readonly :value="hmac" type="textarea" placeholder="The result of the HMAC..." />
</n-form-item>
<n-space justify="center">
<n-button secondary @click="copy()">Copy HMAC</n-button>
<c-button @click="copy()">Copy HMAC</c-button>
</n-space>
</div>
</template>

View File

@ -20,7 +20,7 @@
</n-form-item>
<n-space justify="center">
<n-button secondary @click="copyEscaped"> Copy </n-button>
<c-button @click="copyEscaped"> Copy </c-button>
</n-space>
</n-card>
<n-card title="Unescape html entities">
@ -44,7 +44,7 @@
</n-form-item>
<n-space justify="center">
<n-button secondary @click="copyUnescaped"> Copy </n-button>
<c-button @click="copyUnescaped"> Copy </c-button>
</n-space>
</n-card>
</template>

View File

@ -1,11 +1,9 @@
<template>
<n-tooltip trigger="hover">
<template #trigger>
<n-button circle quaternary :type="isActive?.() ? 'primary' : 'default'" @click="action">
<template #icon>
<n-icon :component="icon" />
</template>
</n-button>
<c-button circle variant="text" :type="isActive?.() ? 'primary' : 'default'" @click="action">
<n-icon :component="icon" />
</c-button>
</template>
{{ title }}

View File

@ -39,10 +39,10 @@
The end IPv4 address is lower than the start IPv4 address. This is not valid and no result could be
calculated. In the most cases the solution to solve this problem is to change start and end address.
</n-text>
<n-button quaternary @click="onSwitchStartEndClicked">
<n-icon :component="ChangeCircleOutlined" />
&nbsp;&nbsp;Switch start and end IPv4 address
</n-button>
<c-button @click="onSwitchStartEndClicked">
<n-icon mr-2 :component="Exchange" depth="3" size="22" />
Switch start and end IPv4 address
</c-button>
</n-space>
</n-alert>
</div>
@ -52,7 +52,7 @@
<script setup lang="ts">
import { useValidation } from '@/composable/validation';
import { ChangeCircleOutlined } from '@vicons/material';
import { Exchange } from '@vicons/tabler';
import { isValidIpv4 } from '../ipv4-address-converter/ipv4-address-converter.service';
import type { Ipv4RangeExpanderResult } from './ipv4-range-expander.types';
import { calculateCidr } from './ipv4-range-expander.service';

View File

@ -20,14 +20,14 @@
</n-table>
<n-space style="margin-top: 14px" justify="space-between">
<n-button tertiary @click="switchToBlock({ count: -1 })">
<c-button @click="switchToBlock({ count: -1 })">
<n-icon :component="ArrowLeft" />
Previous block
</n-button>
<n-button tertiary @click="switchToBlock({ count: 1 })">
</c-button>
<c-button @click="switchToBlock({ count: 1 })">
Next block
<n-icon :component="ArrowRight" />
</n-button>
</c-button>
</n-space>
</div>
</div>

View File

@ -22,7 +22,7 @@
<br />
<br />
<n-space justify="center">
<n-button secondary autofocus @click="copy"> Copy </n-button>
<c-button autofocus @click="copy"> Copy </c-button>
</n-space>
</n-card>
</template>

View File

@ -24,7 +24,7 @@
</n-form-item>
<n-space justify="center">
<n-button :disabled="!details" tertiary> Copy vendor info </n-button>
<c-button :disabled="!details"> Copy vendor info </c-button>
</n-space>
</div>
</template>

View File

@ -5,9 +5,9 @@
<template #suffix>
<n-tooltip trigger="hover">
<template #trigger>
<n-button quaternary circle @click="refreshSecret">
<c-button circle variant="text" @click="refreshSecret">
<n-icon :component="Refresh" />
</n-button>
</c-button>
</template>
Generate secret token
</n-tooltip>
@ -23,7 +23,7 @@
</div>
<n-space justify="center" vertical align="center" style="margin-top: 10px">
<n-image :src="qrcode"></n-image>
<n-button secondary tag="a" :href="keyUri" target="_blank">Open Key URI in new tab</n-button>
<c-button :href="keyUri" target="_blank">Open Key URI in new tab</c-button>
</n-space>
</div>
<div style="max-width: 350px">

View File

@ -8,31 +8,30 @@
<n-input-group>
<n-tooltip trigger="hover" placement="bottom">
<template #trigger>
<n-button data-test-id="previous-otp" secondary @click.prevent="copyPrevious(tokens.previous)">{{
tokens.previous
}}</n-button>
<c-button important:h-12 data-test-id="previous-otp" @click.prevent="copyPrevious(tokens.previous)">
{{ tokens.previous }}
</c-button>
</template>
<div>{{ previousCopied ? 'Copied !' : 'Copy previous OTP' }}</div>
</n-tooltip>
<n-tooltip trigger="hover" placement="bottom">
<template #trigger>
<n-button
tertiary
type="primary"
<c-button
data-test-id="current-otp"
class="current-otp"
important:h-12
@click.prevent="copyCurrent(tokens.current)"
>
{{ tokens.current }}
</n-button>
</c-button>
</template>
<div>{{ currentCopied ? 'Copied !' : 'Copy current OTP' }}</div>
</n-tooltip>
<n-tooltip trigger="hover" placement="bottom">
<template #trigger>
<n-button secondary data-test-id="next-otp" @click.prevent="copyNext(tokens.next)">{{
<c-button important:h-12 data-test-id="next-otp" @click.prevent="copyNext(tokens.next)">{{
tokens.next
}}</n-button>
}}</c-button>
</template>
<div>{{ nextCopied ? 'Copied !' : 'Copy next OTP' }}</div>
</n-tooltip>

View File

@ -28,7 +28,7 @@
<n-gi>
<n-space justify="center" align="center" vertical>
<n-image :src="qrcode" width="200" />
<n-button secondary @click="download"> Download qr-code </n-button>
<c-button @click="download"> Download qr-code </c-button>
</n-space>
</n-gi>
</n-grid>

View File

@ -4,8 +4,8 @@
{{ port }}
</div>
<n-space justify="center">
<n-button secondary @click="copy"> Copy </n-button>
<n-button secondary @click="refreshPort"> Refresh </n-button>
<c-button @click="copy"> Copy </c-button>
<c-button @click="refreshPort"> Refresh </c-button>
</n-space>
</n-card>
</template>

View File

@ -8,9 +8,9 @@
<div class="result">
{{ outputRoman }}
</div>
<n-button secondary autofocus :disabled="validationNumeral.validationStatus === 'error'" @click="copyRoman">
<c-button autofocus :disabled="validationNumeral.validationStatus === 'error'" @click="copyRoman">
Copy
</n-button>
</c-button>
</n-space>
</n-card>
<br />
@ -22,9 +22,7 @@
<div class="result">
{{ outputNumeral }}
</div>
<n-button secondary autofocus :disabled="validationRoman.validationStatus === 'error'" @click="copyArabic">
Copy
</n-button>
<c-button :disabled="validationRoman.validationStatus === 'error'" @click="copyArabic"> Copy </c-button>
</n-space>
</n-card>
</div>

View File

@ -5,7 +5,7 @@
<n-input-number v-model:value="bits" min="256" max="16384" step="8" />
</n-form-item>
<n-button tertiary @click="refreshCerts">Refresh key-pair</n-button>
<c-button @click="refreshCerts">Refresh key-pair</c-button>
</n-space>
</div>

View File

@ -14,7 +14,7 @@
</n-form-item>
<n-space justify="center">
<n-button secondary :disabled="slug.length === 0" @click="copy">Copy slug</n-button>
<c-button :disabled="slug.length === 0" @click="copy">Copy slug</c-button>
</n-space>
</div>
</template>

View File

@ -38,9 +38,9 @@
</n-form-item>
<n-space justify="center">
<n-button secondary @click="copySVG()">Copy svg</n-button>
<n-button secondary @click="copyBase64()">Copy base64</n-button>
<n-button secondary @click="download()">Download svg</n-button>
<c-button @click="copySVG()">Copy svg</c-button>
<c-button @click="copyBase64()">Copy base64</c-button>
<c-button @click="download()">Download svg</c-button>
</n-space>
</div>

View File

@ -11,7 +11,7 @@
</n-card>
<n-space justify="center">
<n-button secondary autofocus @click="copy"> Copy NATO string </n-button>
<c-button autofocus @click="copy"> Copy NATO string </c-button>
</n-space>
</n-space>
</div>

View File

@ -44,8 +44,8 @@
<br />
<br />
<n-space justify="center">
<n-button secondary autofocus @click="copy"> Copy </n-button>
<n-button secondary @click="refreshToken"> Refresh </n-button>
<c-button @click="copy"> Copy </c-button>
<c-button @click="refreshToken"> Refresh </c-button>
</n-space>
</n-card>
</div>

View File

@ -24,7 +24,7 @@
</n-form-item>
<n-space justify="center">
<n-button secondary @click="copyEncoded"> Copy </n-button>
<c-button @click="copyEncoded"> Copy </c-button>
</n-space>
</n-card>
<n-card title="Decode">
@ -52,7 +52,7 @@
</n-form-item>
<n-space justify="center">
<n-button secondary @click="copyDecoded"> Copy </n-button>
<c-button @click="copyDecoded"> Copy </c-button>
</n-space>
</n-card>
</template>

View File

@ -19,8 +19,8 @@
/>
<n-space justify="center">
<n-button secondary autofocus @click="copy"> Copy </n-button>
<n-button secondary @click="refreshUUIDs"> Refresh </n-button>
<c-button autofocus @click="copy"> Copy </c-button>
<c-button @click="refreshUUIDs"> Refresh </c-button>
</n-space>
</n-space>
</template>

View File

@ -0,0 +1,240 @@
import { defineThemes } from '../theme/theme.models';
import { appThemes } from '../theme/themes';
export const { useTheme } = defineThemes({
dark: {
basic: {
default: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'rgba(255, 255, 255, 0.08)',
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'rgba(255, 255, 255, 0.12)',
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'rgba(255, 255, 255, 0.24)',
},
outline: {
color: appThemes.dark.primary.color,
},
},
primary: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.colorPressed,
},
outline: {
color: appThemes.dark.primary.color,
},
},
warning: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.colorPressed,
},
outline: {
color: appThemes.dark.warning.color,
},
},
},
text: {
default: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'transparent',
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'rgba(255, 255, 255, 0.12)',
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: 'rgba(255, 255, 255, 0.82)',
},
outline: {
color: appThemes.dark.primary.color,
},
},
primary: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.primary.colorPressed,
},
outline: {
color: appThemes.dark.primary.color,
},
},
warning: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.dark.warning.colorPressed,
},
outline: {
color: appThemes.dark.warning.color,
},
},
},
},
light: {
basic: {
default: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'rgba(46, 51, 56, 0.05)',
hover: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'rgba(46, 51, 56, 0.09)',
},
pressed: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'rgba(46, 51, 56, 0.22)',
},
outline: {
color: appThemes.light.primary.color,
},
},
primary: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.primary.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.primary.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.primary.colorPressed,
},
outline: {
color: appThemes.light.primary.color,
},
},
warning: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.warning.color,
hover: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.warning.colorHover,
},
pressed: {
textColor: appThemes.dark.text.baseColor,
backgroundColor: appThemes.light.warning.colorPressed,
},
outline: {
color: appThemes.light.warning.color,
},
},
},
text: {
default: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'transparent',
hover: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'rgba(46, 51, 56, 0.09)',
},
pressed: {
textColor: appThemes.light.text.baseColor,
backgroundColor: 'rgba(46, 51, 56, 0.13)',
},
outline: {
color: appThemes.light.primary.color,
},
},
primary: {
textColor: appThemes.light.primary.color,
backgroundColor: 'transparent',
hover: {
textColor: appThemes.light.primary.colorHover,
backgroundColor: 'rgba(46, 51, 56, 0.09)',
},
pressed: {
textColor: appThemes.light.primary.colorPressed,
backgroundColor: 'rgba(46, 51, 56, 0.13)',
},
outline: {
color: appThemes.light.primary.color,
},
},
warning: {
textColor: appThemes.light.warning.color,
backgroundColor: 'transparent',
hover: {
textColor: appThemes.light.warning.colorHover,
backgroundColor: 'rgba(46, 51, 56, 0.09)',
},
pressed: {
textColor: appThemes.light.warning.colorPressed,
backgroundColor: 'rgba(46, 51, 56, 0.13)',
},
outline: {
color: appThemes.light.warning.color,
},
},
},
},
});

View File

@ -0,0 +1,113 @@
<template>
<component
:is="tag"
:href="href ?? to"
class="c-button"
:class="{ disabled, round, circle }"
:to="to"
@click="handleClick"
>
<slot />
</component>
</template>
<script lang="ts" setup>
import type { RouteLocationRaw } from 'vue-router';
import { useTheme } from './c-button.theme';
const props = withDefaults(
defineProps<{
type?: 'default' | 'primary';
variant?: 'basic' | 'text';
disabled?: boolean;
round?: boolean;
circle?: boolean;
href?: string;
to?: RouteLocationRaw;
}>(),
{
type: 'default',
variant: 'basic',
disabled: false,
round: false,
circle: false,
href: undefined,
to: undefined,
},
);
const { variant, disabled, round, circle, href, type, to } = toRefs(props);
const emits = defineEmits(['click']);
function handleClick(event: MouseEvent) {
if (!disabled.value) {
emits('click', event);
}
}
const theme = useTheme();
const variantTheme = computed(() => theme.value[variant.value][type.value]);
const tag = computed(() => {
if (href.value) {
return 'a';
}
if (to.value) {
return 'router-link';
}
return 'button';
});
</script>
<style lang="less" scoped>
.c-button {
margin: 0;
line-height: 1;
font-family: inherit;
font-size: inherit;
border: none;
text-align: center;
cursor: pointer;
text-decoration: none;
height: 34px;
font-weight: 400;
color: v-bind('variantTheme.textColor');
padding: 0 14px;
border-radius: 4px;
transition: background-color cubic-bezier(0.4, 0, 0.2, 1) 0.3s;
background-color: v-bind('variantTheme.backgroundColor');
display: inline-flex;
flex-direction: row;
align-items: center;
justify-content: center;
// outline-offset: 1px;
&.round {
border-radius: 100px;
}
&.circle {
border-radius: 40px;
width: 34px;
}
&:not(.disabled) {
&:hover {
background-color: v-bind('variantTheme.hover.backgroundColor');
}
&:active {
background-color: v-bind('variantTheme.pressed.backgroundColor');
}
}
&:focus {
outline: 2px solid v-bind('variantTheme.outline.color');
}
&.disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
</style>

View File

@ -0,0 +1,39 @@
import { defineThemes } from '../theme/theme.models';
import { appThemes } from '../theme/themes';
export const { useTheme } = defineThemes({
dark: {
default: {
textColor: appThemes.dark.primary.color,
hover: {
textColor: appThemes.dark.primary.colorHover,
},
pressed: {
textColor: appThemes.dark.primary.colorPressed,
},
outline: {
color: appThemes.dark.primary.color,
},
},
},
light: {
default: {
textColor: appThemes.light.primary.color,
hover: {
textColor: appThemes.light.primary.colorHover,
},
pressed: {
textColor: appThemes.light.primary.colorPressed,
},
outline: {
color: appThemes.light.primary.color,
},
},
},
});

49
src/ui/c-link/c-link.vue Normal file
View File

@ -0,0 +1,49 @@
<template>
<component :is="tag" :href="href ?? to" class="c-link" :to="to">
<slot />
</component>
</template>
<script lang="ts" setup>
import { RouterLink, type RouteLocationRaw } from 'vue-router';
import { useTheme } from './c-link.theme';
const props = defineProps<{
href?: string;
to?: RouteLocationRaw;
}>();
const { href, to } = toRefs(props);
const theme = useTheme();
const tag = computed(() => (href?.value ? 'a' : RouterLink));
</script>
<style lang="less" scoped>
.c-link {
line-height: inherit;
font-family: inherit;
font-size: inherit;
border: none;
cursor: pointer;
text-decoration: none;
font-weight: 400;
color: v-bind('theme.default.textColor');
border-radius: 4px;
transition: color cubic-bezier(0.4, 0, 0.2, 1) 0.3s;
outline-offset: 1px;
&:hover {
color: v-bind('theme.default.hover.textColor');
}
&:active {
color: v-bind('theme.default.textColor');
}
&:focus {
color: v-bind('theme.default.outline.color');
}
}
</style>

View File

@ -0,0 +1,13 @@
import { useThemeStore } from './theme.store';
export { defineThemes };
function defineThemes<Theme>(themes: { light: Theme; dark: Theme }) {
return {
themes,
useTheme() {
const themeStore = useThemeStore();
return computed(() => themes[themeStore.themeType]);
},
};
}

View File

@ -0,0 +1,20 @@
import { defineStore } from 'pinia';
export const useThemeStore = defineStore('ui-theme', {
state: () => ({
themeType: useStorage<'dark' | 'light'>('ui-store:theme-type', 'dark') as Ref<'dark' | 'light'>,
}),
getters: {
isDarkTheme(): boolean {
return this.themeType === 'dark';
},
isLightTheme(): boolean {
return this.themeType === 'light';
},
},
actions: {
toggleTheme() {
this.themeType = this.isDarkTheme ? 'light' : 'dark';
},
},
});

37
src/ui/theme/themes.ts Normal file
View File

@ -0,0 +1,37 @@
import { defineThemes } from './theme.models';
export const { themes: appThemes, useTheme: useAppTheme } = defineThemes({
light: {
text: {
baseColor: 'rgb(51, 54, 57)',
},
primary: {
color: '#18a058',
colorHover: '#1ea54c',
colorPressed: '#0C7A43',
},
warning: {
color: '#f59e0b',
colorHover: '#f59e0b',
colorPressed: '#f59e0b',
},
},
dark: {
text: {
baseColor: 'rgba(255, 255, 255, 0.82)',
},
primary: {
color: '#1ea54c',
colorHover: '#36AD6A',
colorPressed: '#0C7A43',
},
warning: {
color: '#f59e0b',
colorHover: '#f59e0b',
colorPressed: '#f59e0b',
},
},
});

View File

@ -73,6 +73,9 @@ export default defineConfig({
},
}),
Components({
dirs: ['src/'],
extensions: ['vue', 'md'],
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
resolvers: [NaiveUiResolver()],
}),
Unocss(),