styling; edit existing modal
This commit is contained in:
parent
b672a46746
commit
b63ae715a2
@ -1,17 +1,20 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const {active} = defineProps({
|
const {active} = defineProps({
|
||||||
active: Boolean
|
active: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="wrapper" :class="{active: active}">
|
<div class="btn-wrapper" :class="{active: active}">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
div.wrapper {
|
div.btn-wrapper {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin: 4px 8px 0 0;
|
margin: 4px 8px 0 0;
|
||||||
|
|||||||
91
frontend/wizard-vue/src/components/EditUrlModal.vue
Normal file
91
frontend/wizard-vue/src/components/EditUrlModal.vue
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import Field from "@/components/Field.vue";
|
||||||
|
import {type Field as FieldSpec} from "@/urlmaker/specs";
|
||||||
|
import {validateUrl} from "@/urlmaker/validators.ts";
|
||||||
|
import Btn from "@/components/Btn.vue";
|
||||||
|
import {onMounted, onUnmounted, ref, watch} from "vue";
|
||||||
|
|
||||||
|
const field: FieldSpec = {
|
||||||
|
name: '',
|
||||||
|
input_type: 'url',
|
||||||
|
label: 'URL of feed for editing',
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
validate: validateUrl,
|
||||||
|
}
|
||||||
|
|
||||||
|
const {visible, modelValue} = defineProps({
|
||||||
|
visible: Boolean,
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['close', 'update:modelValue']);
|
||||||
|
|
||||||
|
const url = ref(modelValue);
|
||||||
|
watch(() => visible, () => {
|
||||||
|
url.value = modelValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
const valid = ref(false);
|
||||||
|
watch(url, (value) => {
|
||||||
|
valid.value = field.validate(value).ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
const accept = () => {
|
||||||
|
valid.value = field.validate(url.value).ok;
|
||||||
|
if (valid.value) {
|
||||||
|
emit('update:modelValue', url.value);
|
||||||
|
emit('close');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const listener = (e: KeyboardEvent) => {
|
||||||
|
if (e.code === 'Escape') emit('close');
|
||||||
|
if (e.code === 'Enter') accept();
|
||||||
|
};
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener('keyup', listener);
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.removeEventListener('keyup', listener);
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Teleport to="#app">
|
||||||
|
<div class="modal-wrapper" v-if="visible" @click="$emit('close')">
|
||||||
|
<div class="modal" @click.stop>
|
||||||
|
<Field :field="field" v-model="url" :focused="true"/>
|
||||||
|
<Btn :active="valid" @click="accept">Edit</Btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
div.modal-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
background: rgba(200, 200, 200, 0.5);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.modal {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 400px;
|
||||||
|
margin: auto auto;
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: #a0a0a0 1px 2px 2px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,20 +1,26 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type {Field} from "@/urlmaker/specs.ts";
|
import type {Field} from "@/urlmaker/specs.ts";
|
||||||
import {getCurrentInstance} from "vue";
|
import {getCurrentInstance, onMounted, useTemplateRef} from "vue";
|
||||||
|
|
||||||
defineProps<{
|
const {field, focused} = defineProps<{
|
||||||
field: Field
|
field: Field,
|
||||||
|
focused: boolean,
|
||||||
}>();
|
}>();
|
||||||
const id = 'field' + getCurrentInstance()?.uid;
|
const id = 'field' + getCurrentInstance()?.uid;
|
||||||
const model = defineModel();
|
const model = defineModel();
|
||||||
|
|
||||||
|
const inputRef = useTemplateRef('field');
|
||||||
|
onMounted(() => {
|
||||||
|
if(focused) inputRef.value?.focus();
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="label"><label :for="id">{{ field.label }}</label></div>
|
<div class="label"><label :for="id">{{ field.label }}</label></div>
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<input :type="field.input_type" :name="field.name" :id="id" v-model="model"/>
|
<input :type="field.input_type" :name="field.name" :id="id" v-model="model" ref="field"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -23,4 +29,17 @@ const model = defineModel();
|
|||||||
div.field {
|
div.field {
|
||||||
margin: 0 0 8px 0;
|
margin: 0 0 8px 0;
|
||||||
}
|
}
|
||||||
|
div.label {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
div.input {
|
||||||
|
margin: 2px 0 0 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
input {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {reactive, ref, watch} from "vue";
|
|||||||
import {type Field, fields, type Specs} from "@/urlmaker/specs.ts";
|
import {type Field, fields, type Specs} from "@/urlmaker/specs.ts";
|
||||||
import Btn from "@/components/Btn.vue";
|
import Btn from "@/components/Btn.vue";
|
||||||
import Copyable from "@/components/Copyable.vue";
|
import Copyable from "@/components/Copyable.vue";
|
||||||
|
import EditUrlModal from "@/components/EditUrlModal.vue";
|
||||||
|
|
||||||
const emptySpecs = fields.reduce((o, f) => {
|
const emptySpecs = fields.reduce((o, f) => {
|
||||||
o[f.name] = f.default;
|
o[f.name] = f.default;
|
||||||
@ -18,21 +19,35 @@ watch(specs, (value, oldValue) => {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
const link = ref("https://kek.com");
|
const existingLink = ref("");
|
||||||
|
const link = ref("");
|
||||||
|
const editModalVisible = ref(false);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<SpecsForm v-model="specs" class="specs-form"></SpecsForm>
|
<div class="wrapper">
|
||||||
<Btn :active="formValid">Generate link</Btn>
|
<SpecsForm v-model="specs" class="specs-form"></SpecsForm>
|
||||||
<Btn :active="formValid">Screenshot</Btn>
|
<Btn :active="formValid">Generate link</Btn>
|
||||||
<Copyable v-if="link" :contents="link" class="link-view"></Copyable>
|
<Btn :active="formValid">Screenshot</Btn>
|
||||||
|
<Btn @click="editModalVisible = true">Edit existing task</Btn>
|
||||||
|
<Copyable v-if="link" :contents="link" class="link-view"></Copyable>
|
||||||
|
<EditUrlModal :visible="editModalVisible" @close="editModalVisible = false"
|
||||||
|
v-model="existingLink"></EditUrlModal>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
div.wrapper {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.specs-form {
|
.specs-form {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-view {
|
.link-view {
|
||||||
margin-top: 15px !important;
|
margin-top: 15px !important;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user