Skip to content

Commit

Permalink
extract operations arrays component for reuse with :is, :where, and :…
Browse files Browse the repository at this point in the history
…not args, and properly design selector delete button
  • Loading branch information
AlexVipond committed May 18, 2021
1 parent 8d11259 commit e18a078
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 93 deletions.
75 changes: 10 additions & 65 deletions src/interface/CssSelectorBuilder.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<header class="bg-denim-1000 px-6 pt-8 flex">
<nav class="mr-auto flex items-center gap-4">
<PopoverHelp :selector="selector" />
<PopoverHelp :operated="operated" />
<a
href="https://github.com/AlexVipond/css-selector-builder"
class="btn--grows rounded-full p-1 focus:outline-none focus-visible:ring-2 focus-visible:ring-violet-300 focus-visible:ring-opacity-75"
Expand Down Expand Up @@ -33,7 +33,7 @@
class="relative w-full max-w-xl btn--grows rounded-md text-violet-100 text-xl"
@click="() => copyable.copy()"
>
<pre class="w-full p-4 brand-gradient-to-r overflow-x-scroll rounded-md shadow-lg text-left"><code>{{ selector || '*' }}</code></pre>
<pre class="w-full p-4 brand-gradient-to-r overflow-x-scroll rounded-md shadow-lg text-left"><code>{{ operated || '*' }}</code></pre>
<transition
enter-active-class="transition duration-100 delay-125 ease-in"
enter-from-class="opacity-0"
Expand Down Expand Up @@ -72,56 +72,8 @@
</transition>
</button>
</section>
<section class="w-full max-w-xl flex flex-col gap-8">
<transition-group
enter-active-class="transition duration-100 ease-in"
enter-from-class="opacity-0"
enter-to-class="opacity-100"
leave-active-class="transition duration-100 ease-in"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
moveClass="transition duration-100"
>
<div
v-for="(operations, index) in operationsArrays"
:key="index"
class="flex flex-col gap-8"
>
<div class="flex flex-col gap-4">
<button
type="button"
name="Delete condition"
class="ml-auto flex-shrink-0 p-1 btn--raised btn--grows bg-[#AD4040] text-[#FED7D7] rounded-full"
@click="() => operationsArrays = createDelete({ index })(operationsArrays)"
>
<TrashIcon class="h-5 w-5" />
</button>
<FormOperations
:modelValue="operations"
@update:modelValue="newOperations => operationsArrays = createReplace({ index, item: newOperations })(operationsArrays)"
:isTopLevel="true"
/>
</div>
<div
v-if="index !== operationsArrays.length - 1"
class="flex items-center justify-center gap-3 font-mono"
>
<div class="h-px w-16 bg-denim-500" />
<h3 class="uppercase text-xl tracking-[0.2em] flex-shrink-0 text-denim-500" >
or
</h3>
<div class="h-px w-16 bg-denim-500" />
</div>
</div>
</transition-group>
<button
name="Add conditions for another selector"
class="mx-auto p-3 text-lg btn--raised btn--grows rounded-full p-3 bg-gradient-to-r from-denim-700 to-denim-600 flex-shrink-0 text-denim-100"
@click="operationsArrays = [...operationsArrays, []]"
type="button"
>
OR
</button>
<section class="w-full max-w-xl">
<FormOperationsArrays v-model="operationsArrays" :isTopLevel="true" />
</section>
</main>
<footer class="flex flex-col gap-6 bg-denim-1200 px-6 py-8 text-denim-300">
Expand Down Expand Up @@ -151,35 +103,32 @@ import {
SimpleNPM,
} from '@baleada/vue-simple-icons'
import { useCopyable } from '@baleada/vue-composition'
import { createReplace, createDelete, createReorder } from '@baleada/logic'
import {
CheckIcon,
ClipboardCopyIcon,
} from '@heroicons/vue/solid'
import { TrashIcon } from '@heroicons/vue/outline'
import { toOperated } from './toOperated'
import type { Operation } from './toOperated'
import FormOperations from './components/FormOperations.vue'
import FormOperationsArrays from './components/FormOperationsArrays.vue'
import PopoverHelp from './components/PopoverHelp.vue'
export default defineComponent({
components: {
FormOperations,
FormOperationsArrays,
SimpleTwitter,
SimpleGitHub,
SimpleNPM,
PopoverHelp,
CheckIcon,
ClipboardCopyIcon,
TrashIcon,
},
setup () {
const operationsArrays = ref<Operation[][]>([[]]),
selector = computed(() => operationsArrays.value.map(toOperated).join(', ')),
operated = computed(() => operationsArrays.value.map(toOperated).filter(o => o !== '').join(', ')),
clipboard = { text: '' },
copyable = useCopyable(selector.value, { clipboard })
copyable = useCopyable(operated.value, { clipboard })
watch(selector, async () => copyable.value.string = selector.value)
watch(operated, async () => copyable.value.string = operated.value)
onMounted(() => {
const urlOperationsArrays = new URL(window.location.toString()).searchParams.get('conditions')
Expand All @@ -197,14 +146,10 @@ export default defineComponent({
}
)
return {
operationsArrays,
selector,
operated,
copyable,
createReplace,
createDelete,
createReorder,
}
}
})
Expand Down
4 changes: 2 additions & 2 deletions src/interface/components/BaseListbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ import {
ListboxOption,
} from '@headlessui/vue'
import { CheckIcon, SelectorIcon } from '@heroicons/vue/solid'
import { NESTED_STATUS_SYMBOL } from '../state'
import { OPERATIONS_NESTED_STATUS_SYMBOL } from '../state'
export default defineComponent({
components: {
Expand All @@ -86,7 +86,7 @@ export default defineComponent({
emit('update:modelValue', newValue)
}
}),
isNestedVariant = inject<boolean>(NESTED_STATUS_SYMBOL)
isNestedVariant = inject<boolean>(OPERATIONS_NESTED_STATUS_SYMBOL)
return { selectedOption, isNestedVariant }
}
Expand Down
4 changes: 2 additions & 2 deletions src/interface/components/BaseRadioGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
RadioGroupLabel,
RadioGroupOption,
} from '@headlessui/vue'
import { NESTED_STATUS_SYMBOL } from '../state'
import { OPERATIONS_NESTED_STATUS_SYMBOL } from '../state'
export default defineComponent({
components: {
Expand All @@ -51,7 +51,7 @@ export default defineComponent({
emit('update:modelValue', newValue)
}
}),
isNestedVariant = inject<boolean>(NESTED_STATUS_SYMBOL)
isNestedVariant = inject<boolean>(OPERATIONS_NESTED_STATUS_SYMBOL)
return { selectedOption, isNestedVariant }
}
Expand Down
4 changes: 2 additions & 2 deletions src/interface/components/FormArg.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import {
attributeOperators,
directionalities
} from '../options'
import { NESTED_STATUS_SYMBOL } from '../state'
import { OPERATIONS_NESTED_STATUS_SYMBOL } from '../state'
export default defineComponent({
components: {
Expand Down Expand Up @@ -96,7 +96,7 @@ export default defineComponent({
}
})(),
modelledOption = ref(optionDefault),
isNestedVariant = inject<boolean>(NESTED_STATUS_SYMBOL)
isNestedVariant = inject<boolean>(OPERATIONS_NESTED_STATUS_SYMBOL)
watch(
Expand Down
4 changes: 2 additions & 2 deletions src/interface/components/FormOperation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import type { Operation } from '../toOperated'
import InputPipe from './InputPipe.vue'
import FormArg from './FormArg.vue'
import { pipeMetadata } from '../pipeMetadata'
import { NESTED_STATUS_SYMBOL } from '../state'
import { OPERATIONS_NESTED_STATUS_SYMBOL } from '../state'
export default defineComponent({
components: {
Expand Down Expand Up @@ -95,7 +95,7 @@ export default defineComponent({
emitMoveDown = () => {
emit('moveDown', operation.value)
},
isNestedVariant = inject<boolean>(NESTED_STATUS_SYMBOL)
isNestedVariant = inject<boolean>(OPERATIONS_NESTED_STATUS_SYMBOL)
return {
operation,
Expand Down
12 changes: 6 additions & 6 deletions src/interface/components/FormOperations.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<template>
<section
class="flex flex-col gap-10 rounded-md shadow-lg"
class="flex flex-col gap-10 rounded-md shadow-lg pb-10"
:class="[
isNestedVariant ? 'bg-denim-600 text-denim-100' : 'bg-denim-800 text-denim-200',
nestingLevel === 0 ? 'px-6 py-8' : 'px-4 py-6'
nestingLevel === 0 ? 'px-6 pt-8' : 'px-4 pt-6'
]"
>
<h2
Expand Down Expand Up @@ -79,7 +79,7 @@ import { PlusIcon } from '@heroicons/vue/solid'
import type { Operation } from '../toOperated'
import FormOperation from './FormOperation.vue'
import { pipeMetadata } from '../pipeMetadata'
import { NESTING_LEVEL_SYMBOL, NESTED_STATUS_SYMBOL } from '../state'
import { OPERATIONS_NESTING_LEVEL_SYMBOL, OPERATIONS_NESTED_STATUS_SYMBOL } from '../state'
export default defineComponent({
name: 'FormOperations',
Expand Down Expand Up @@ -130,11 +130,11 @@ export default defineComponent({
const index = findOperationIndex({ id: operation.id, operations })
operations.value = createReorder<Operation>({ from: index, to })(operations.value)
},
nestingLevel = shallowRef(props.isTopLevel ? 0 : inject<number>(NESTING_LEVEL_SYMBOL) + 1),
nestingLevel = shallowRef(props.isTopLevel ? 0 : inject<number>(OPERATIONS_NESTING_LEVEL_SYMBOL) + 1),
isNestedVariant = shallowRef(nestingLevel.value % 2 !== 0)
provide(NESTING_LEVEL_SYMBOL, nestingLevel.value)
provide(NESTED_STATUS_SYMBOL, isNestedVariant.value)
provide(OPERATIONS_NESTING_LEVEL_SYMBOL, nestingLevel.value)
provide(OPERATIONS_NESTED_STATUS_SYMBOL, isNestedVariant.value)
return {
operations,
Expand Down
124 changes: 124 additions & 0 deletions src/interface/components/FormOperationsArrays.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<template>
<section class="flex flex-col gap-8">
<transition-group
enter-active-class="transition duration-100 ease-in"
enter-from-class="opacity-0"
enter-to-class="opacity-100"
leave-active-class="transition duration-100 ease-in"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
moveClass="transition duration-100"
>
<div
v-for="(operations, index) in operationsArrays"
:key="index"
class="flex flex-col gap-14"
>
<div
class="relative rounded-md transition duration-75"
:class="statuses[index] === 'ready to delete' ? 'ring ring-[#AD4040] ring-offset-4 ring-offset-denim-1000' : ''"
>
<FormOperations
:modelValue="operations"
@update:modelValue="newOperations => operationsArrayUpdate(index, newOperations)"
:isTopLevel="true"
/>
<div class="btn--raised btn--grows absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-1/2 rounded-full">
<button
type="button"
name="Delete condition"
class="p-2 text-base rounded-full bg-[#AD4040] text-[#FED7D7] flex-shrink-0 text-denim-100"
@click="() => operationsArrayDelete(index)"
@mouseenter="() => readyToDelete(index)"
@focus="() => readyToDelete(index)"
@mouseleave="() => notReadyToDelete(index)"
@blur="() => notReadyToDelete(index)"
>
<TrashIcon class="h-5 w-5" />
</button>
</div>
</div>
<div
v-if="index !== operationsArrays.length - 1"
class="flex items-center justify-center gap-3 font-mono"
>
<div class="h-px w-16 bg-denim-500" />
<h3 class="uppercase text-xl tracking-[0.2em] flex-shrink-0 text-denim-500" >
or
</h3>
<div class="h-px w-16 bg-denim-500" />
</div>
</div>
</transition-group>
<button
name="Add conditions for another selector"
class="mx-auto p-3 text-lg btn--raised btn--grows rounded-full bg-gradient-to-r from-denim-700 to-denim-600 flex-shrink-0 text-denim-100"
@click="operationsArrayCreate"
type="button"
>
OR
</button>
</section>
</template>

<script lang="ts">
import { computed, ref, shallowRef, provide, inject } from 'vue'
import { TrashIcon } from '@heroicons/vue/outline'
import { createReplace, createDelete } from '@baleada/logic'
import FormOperations from './FormOperations.vue'
import { OPERATIONS_ARRAYS_NESTED_STATUS_SYMBOL, OPERATIONS_ARRAYS_NESTING_LEVEL_SYMBOL } from '../state'
import type { Operation } from '../toOperated'
import { defineComponent } from 'vue'
export default defineComponent({
components: {
FormOperations,
TrashIcon,
},
props: ['modelValue', 'isTopLevel'],
setup (props, { emit }) {
const operationsArrays = computed<Operation[][]>({
get: () => props.modelValue,
set: newOperationsArrays => {
emit('update:modelValue', newOperationsArrays)
}
}),
statuses = ref(operationsArrays.value.map(() => 'not ready to delete')),
readyToDelete = (index: number) => {
statuses.value = createReplace({ index, item: 'ready to delete' })(operationsArrays.value.map(() => 'not ready to delete'))
},
notReadyToDelete = (index: number) => {
statuses.value = createReplace({ index, item: 'not ready to delete' })(statuses.value)
},
operationsArrayCreate = () => {
operationsArrays.value = [
...operationsArrays.value,
[]
]
},
operationsArrayDelete = (index: number) => {
operationsArrays.value = createDelete<Operation[]>({ index })(operationsArrays.value)
},
operationsArrayUpdate = (index: number, operations: Operation[]) => {
operationsArrays.value = createReplace<Operation[]>({ index, item: operations })(operationsArrays.value)
},
nestingLevel = shallowRef(props.isTopLevel ? 0 : inject<number>(OPERATIONS_ARRAYS_NESTING_LEVEL_SYMBOL) + 1),
isNestedVariant = shallowRef(nestingLevel.value % 2 !== 0)
provide(OPERATIONS_ARRAYS_NESTING_LEVEL_SYMBOL, nestingLevel.value)
provide(OPERATIONS_ARRAYS_NESTED_STATUS_SYMBOL, isNestedVariant.value)
return {
operationsArrays,
operationsArrayCreate,
operationsArrayDelete,
operationsArrayUpdate,
nestingLevel,
isNestedVariant,
statuses,
readyToDelete,
notReadyToDelete,
}
}
})
</script>
4 changes: 2 additions & 2 deletions src/interface/components/InputNthPattern.vue
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ import {
ListboxOption,
} from '@headlessui/vue'
import { CheckIcon, SelectorIcon } from '@heroicons/vue/solid'
import { NESTED_STATUS_SYMBOL } from '../state'
import { OPERATIONS_NESTED_STATUS_SYMBOL } from '../state'
export default defineComponent({
components: {
Expand Down Expand Up @@ -214,7 +214,7 @@ export default defineComponent({
]),
stopPropagation = (event: KeyboardEvent | MouseEvent) => event.stopPropagation(),
enterHandle = (index: number) => selectedOption.value = options.value[index],
isNestedVariant = inject<boolean>(NESTED_STATUS_SYMBOL)
isNestedVariant = inject<boolean>(OPERATIONS_NESTED_STATUS_SYMBOL)
return {
options,
Expand Down
Loading

0 comments on commit e18a078

Please sign in to comment.