317 lines
No EOL
7.2 KiB
Vue
317 lines
No EOL
7.2 KiB
Vue
<template>
|
|
<div v-if="isDemoMode && isOpen" class="modal">
|
|
<div
|
|
class="modal__wrapper"
|
|
>
|
|
<demo-ui-button
|
|
@click="appStore.setDemoSettings(false)"
|
|
class="modal__close"
|
|
>
|
|
<Icon name="material-symbols:close" size="30" />
|
|
</demo-ui-button>
|
|
<h2 class="modal__title">{{ toConstantCase(t('demo.settings.title')) }}</h2>
|
|
<div class="modal__inner">
|
|
<div class="modal__block">
|
|
<h3 class="modal__block-title">{{ toConstantCase(t('demo.settings.ui')) }}</h3>
|
|
<div
|
|
v-for="(flag, idx) in availableFlags"
|
|
:key="flag.key"
|
|
class="modal__block-item"
|
|
>
|
|
<demo-ui-checkbox
|
|
:label="toConstantCase(flag.label)"
|
|
v-model="localFlags[flag.key]"
|
|
:id="idx"
|
|
/>
|
|
<p>{{ flag.description }}</p>
|
|
</div>
|
|
</div>
|
|
<demo-ui-button @click="showCodePreview = !showCodePreview">{{ toConstantCase(t('demo.buttons.generateCode')) }}</demo-ui-button>
|
|
<div v-if="showCodePreview" class="modal__preview">
|
|
<div class="modal__preview-wrapper">
|
|
<pre class="modal__preview-code"><code class="language-typescript">{{ codePreview }}</code></pre>
|
|
<demo-ui-button
|
|
@click="copyConfig"
|
|
class="modal__preview-button"
|
|
>
|
|
<Icon name="material-symbols:content-copy" size="16" />
|
|
</demo-ui-button>
|
|
</div>
|
|
<p class="modal__preview-text">{{ t('demo.preview.text') }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="modal__buttons">
|
|
<demo-ui-button @click="resetToDefault">
|
|
<Icon name="material-symbols:refresh" size="20" />
|
|
{{ toConstantCase(t('demo.buttons.reset')) }}
|
|
</demo-ui-button>
|
|
<demo-ui-button @click="saveChanges">
|
|
<Icon name="material-symbols:save" size="20" />
|
|
{{ toConstantCase(t('demo.buttons.save')) }}
|
|
</demo-ui-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useProjectConfig } from '@composables/config';
|
|
|
|
const appStore = useAppStore();
|
|
const {t} = useI18n();
|
|
|
|
const isOpen = computed(() => appStore.isDemoSettings);
|
|
|
|
const {
|
|
isDemoMode,
|
|
availableFlags,
|
|
setDemoFlag,
|
|
resetDemoFlags,
|
|
uiConfig,
|
|
generateConfigCode,
|
|
copyToClipboard
|
|
} = useProjectConfig();
|
|
|
|
const showCodePreview = ref<boolean>(false);
|
|
const localFlags = ref<Record<string, boolean>>({});
|
|
|
|
const previewConfig = computed(() => {
|
|
const config: Record<string, boolean> = {};
|
|
availableFlags.value.forEach(flag => {
|
|
config[flag.key] = localFlags.value[flag.key] !== undefined
|
|
? localFlags.value[flag.key]
|
|
: flag.value;
|
|
});
|
|
|
|
return config;
|
|
});
|
|
|
|
const formatPreviewConfig = (config: Record<string, boolean>): string => {
|
|
const entries = Object.entries(config)
|
|
.map(([key, value]) => ` ${key}: ${value}`)
|
|
.join(',\n');
|
|
|
|
return `ui: {\n${entries}\n}`;
|
|
};
|
|
|
|
function toConstantCase(text: string): string {
|
|
const placeholders: string[] = [];
|
|
let placeholderIndex = 0;
|
|
|
|
const textWithPlaceholders = text.replace(/(['"])(.*?)\1/g, (match) => {
|
|
placeholders.push(match);
|
|
return `__QUOTE_PLACEHOLDER_${placeholderIndex++}__`;
|
|
});
|
|
|
|
let result = textWithPlaceholders
|
|
.toUpperCase()
|
|
.replace(/\s+/g, '_')
|
|
.replace(/[^A-Z0-9_]/g, '');
|
|
|
|
placeholders.forEach((placeholder, index) => {
|
|
result = result.replace(`__QUOTE_PLACEHOLDER_${index}__`, placeholder);
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
watch(isOpen, (newVal) => {
|
|
if (newVal) {
|
|
const flags: Record<string, boolean> = {};
|
|
availableFlags.value.forEach(flag => {
|
|
flags[flag.key] = flag.value;
|
|
});
|
|
localFlags.value = flags;
|
|
}
|
|
}, { immediate: true });
|
|
|
|
const saveChanges = () => {
|
|
availableFlags.value.forEach(flag => {
|
|
const newValue = localFlags.value[flag.key];
|
|
const oldValue = flag.value;
|
|
|
|
if (newValue !== oldValue) {
|
|
setDemoFlag(flag.key, newValue);
|
|
}
|
|
});
|
|
appStore.setDemoSettings(false);
|
|
};
|
|
|
|
const resetToDefault = () => {
|
|
resetDemoFlags();
|
|
appStore.setDemoSettings(false);
|
|
};
|
|
|
|
const copyConfig = async () => {
|
|
const code = codePreview.value;
|
|
await copyToClipboard(code);
|
|
};
|
|
|
|
const codePreview = computed(() => {
|
|
return formatPreviewConfig(previewConfig.value);
|
|
});
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.modal {
|
|
position: fixed;
|
|
z-index: 3;
|
|
width: 100vw;
|
|
height: 100vh;
|
|
top: 0;
|
|
right: 0;
|
|
left: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
backdrop-filter: blur(3px);
|
|
|
|
&__wrapper {
|
|
position: absolute;
|
|
z-index: 2;
|
|
inset: 100px;
|
|
background-color: #0d0d0d;
|
|
padding: 50px;
|
|
border-radius: $default_border_radius;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
gap: 50px;
|
|
}
|
|
|
|
&__close {
|
|
position: absolute;
|
|
z-index: 1;
|
|
top: 15px;
|
|
right: 15px;
|
|
padding: 7px !important;
|
|
}
|
|
|
|
&__title {
|
|
text-align: center;
|
|
font-size: 40px;
|
|
font-weight: 500;
|
|
text-shadow: 0 0 5px $accentNeon;
|
|
text-transform: uppercase;
|
|
color: $accentNeon;
|
|
}
|
|
|
|
&__inner {
|
|
height: 100%;
|
|
width: 100%;
|
|
overflow: auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 50px;
|
|
padding: 10px 20px;
|
|
scrollbar-color: $accentNeon transparent;
|
|
}
|
|
|
|
&__block {
|
|
align-self: flex-start;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 15px;
|
|
|
|
&-title {
|
|
width: fit-content;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 5px;
|
|
border-bottom: 2px solid $accentNeon;
|
|
color: $accentNeon;
|
|
font-weight: 500;
|
|
text-shadow: 0 0 5px $accentNeon;
|
|
text-transform: uppercase;
|
|
font-size: 22px;
|
|
}
|
|
|
|
&-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 5px;
|
|
|
|
& p {
|
|
padding-left: 50px;
|
|
color: #8c8c8c;
|
|
font-weight: 500;
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
}
|
|
|
|
&__preview {
|
|
width: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
|
|
&-wrapper {
|
|
position: relative;
|
|
background-color: #1a1a1a;
|
|
border-radius: $default_border_radius;
|
|
padding: 20px;
|
|
border: 1px solid rgba($accentNeon, 0.3);
|
|
}
|
|
|
|
&-code {
|
|
margin: 0;
|
|
color: #f8f8f2;
|
|
font-family: 'Fira Code', 'Courier New', monospace;
|
|
font-size: 14px;
|
|
line-height: 1.5;
|
|
white-space: pre-wrap;
|
|
overflow-x: auto;
|
|
|
|
.language-typescript {
|
|
color: #f8f8f2;
|
|
|
|
.keyword {
|
|
color: lch(69.03% 60.03 345.46);
|
|
}
|
|
|
|
.string {
|
|
color: #f1fa8c;
|
|
}
|
|
|
|
.number {
|
|
color: #bd93f9;
|
|
}
|
|
|
|
.boolean {
|
|
color: #ff79c6;
|
|
}
|
|
|
|
.property {
|
|
color: #8be9fd;
|
|
}
|
|
}
|
|
}
|
|
|
|
&-button {
|
|
position: absolute;
|
|
top: 10px;
|
|
right: 10px;
|
|
padding: 6px 12px !important;
|
|
font-size: 12px !important;
|
|
gap: 6px !important;
|
|
}
|
|
|
|
&-text {
|
|
color: #8c8c8c;
|
|
font-weight: 500;
|
|
font-size: 14px;
|
|
text-align: center;
|
|
}
|
|
}
|
|
|
|
&__buttons {
|
|
border-top: 1px solid $white;
|
|
padding-top: 25px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 25px;
|
|
}
|
|
}
|
|
</style> |