styling; edit existing modal

This commit is contained in:
Egor Aristov 2025-02-04 15:23:39 +03:00
parent b672a46746
commit b63ae715a2
Signed by: egor3f
GPG Key ID: 40482A264AAEC85F
4 changed files with 140 additions and 12 deletions

View File

@ -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;

View 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>

View File

@ -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>

View File

@ -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>
<div class="wrapper">
<SpecsForm v-model="specs" class="specs-form"></SpecsForm> <SpecsForm v-model="specs" class="specs-form"></SpecsForm>
<Btn :active="formValid">Generate link</Btn> <Btn :active="formValid">Generate link</Btn>
<Btn :active="formValid">Screenshot</Btn> <Btn :active="formValid">Screenshot</Btn>
<Btn @click="editModalVisible = true">Edit existing task</Btn>
<Copyable v-if="link" :contents="link" class="link-view"></Copyable> <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;
} }