Skip to content

Commit

Permalink
fix: image overlay settings
Browse files Browse the repository at this point in the history
  • Loading branch information
arpowers committed Sep 20, 2022
1 parent 264ef38 commit c61f31d
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 150 deletions.
2 changes: 1 addition & 1 deletion @factor/api/plugin-media/index.ts
Expand Up @@ -8,7 +8,7 @@ import { FactorAws } from "../plugin-aws"
import { QueryMediaAction, QueryMediaIndex, QuerySaveMedia } from "./queries"
import { QueryUnsplash } from "./query-unsplash"
import { mediaTable } from "./tables"
export * from "./utils"

type FactorMediaSettings = {
factorUser?: FactorUser
factorDb?: FactorDb
Expand Down
52 changes: 0 additions & 52 deletions @factor/api/plugin-media/utils.ts

This file was deleted.

2 changes: 1 addition & 1 deletion @factor/ui/ElButton.vue
Expand Up @@ -105,7 +105,7 @@ const btnClass = vue.computed(() => {
let sizeClasses = "px-2.5 py-1.5 text-sm"
if (btn == "theme") {
sizeClasses = "px-input-x py-input-y text-input-size"
sizeClasses = "px-[1em] py-[.35em] text-input-size"
} else if (props.size == "md") {
sizeClasses = "px-3 py-1.5 text-base"
} else if (props.size == "sm") {
Expand Down
25 changes: 3 additions & 22 deletions @factor/ui/InputGradient.vue
Expand Up @@ -61,6 +61,7 @@
import { vue, DraggableList } from "@factor/api"
import InputColor from "./InputColor.vue"
import InputRange from "./InputRange.vue"
import { getGradientCss } from "./utils"
const colorEl = vue.ref<HTMLElement>()
/**
Expand All @@ -86,32 +87,12 @@ const emit = defineEmits<{
(event: "update:modelValue", payload: GradientSetting): void
}>()

const getGradientValue = (
value?: GradientSetting,
options?: { noAngle?: boolean },
): string => {
const { noAngle } = options || {}
if (!value?.stops) return ""

const st = value.stops.map((i) => i.color).filter(Boolean)

// to force render if only one stop
if (st.length == 1) {
st.push(st[0])
}

const li = st.join(", ")

const angle = noAngle || !value.angle ? 90 : value.angle
return li ? `linear-gradient(${angle}deg, ${li})` : ""
}

const gradientCss = vue.computed(() => {
return getGradientValue(props.modelValue)
return getGradientCss(props.modelValue)
})

const updateValue = async (value: GradientSetting): Promise<void> => {
value.css = getGradientValue(value)
value.css = getGradientCss(value)
emit("update:modelValue", value)
}

Expand Down
162 changes: 100 additions & 62 deletions @factor/ui/InputMediaEdit.vue
Expand Up @@ -33,72 +33,81 @@
</div>
</div>
</div>
<ElModal v-model:vis="vis" modal-class="max-w-xl">
<div v-if="editingItem">
<img
:src="editingItem.url"
:style="{
filter: editingItem.filters?.map((_) => _.value).join(' '),
}"
/>
<div class=" ">
<div class="mx-auto max-w-sm p-4">
<div class="border-theme-300 mt-4 rounded-md border p-4">
<ElModal v-model:vis="vis" modal-class="max-w-3xl">
<div v-if="editingItem" class="grid-cols-12 md:grid">
<div class="relative col-span-6">
<img
class="z-0 h-full w-full object-cover"
:src="editingItem.url"
:style="{
filter: editingItem.filters?.map((_) => _.value).join(' '),
}"
/>
<div class="absolute inset-0 z-10" :style="overlayStyle"></div>
</div>
<div class="col-span-6 max-h-96 min-h-0 overflow-scroll">
<div class="mx-auto max-w-sm space-y-4 p-4 md:p-6">
<div class="flex items-center justify-between">
<div class="text-theme-300 font-semibold">Edit Image</div>
<ElButton btn="theme" size="xs" @click="vis = false"
>Close</ElButton
>
</div>
<div class="border-theme-300 rounded-md border p-4">
<div class="text-theme-300 mb-2 text-xs font-semibold uppercase">
Filters
</div>
<div class="mb-2 text-sm">
<InputDropDown
default-text="Add Image Filter"
:list="
imageFilters.filter(
(filt) => !filters.some((f) => f.filter == filt),
)
"
direction="up"
@update:model-value="
updateFilters({ filter: $event as ImageFilter })
"
></InputDropDown>
</div>
<div class="space-y-4">
<div class="mb-2 text-sm">
<InputDropDown
default-text="Add Image Filter"
:list="
imageFilters.filter(
(filt) => !filters.some((f) => f.filter == filt),
)
"
@update:model-value="
updateFilters({ filter: $event as ImageFilter })
"
></InputDropDown>
</div>
<div
v-for="(f, i) in filters"
:key="i"
class="flex items-center justify-between space-x-2"
>
<InputRange
:model-value="f.percent"
@update:model-value="
updateFilters({ filter: f.filter, percent: $event })
"
></InputRange>
<div class="flex grow justify-between">
<span
class="bg-theme-500 text-theme-0 inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize"
>
{{ f.filter }}</span
>
<span
class="bg-theme-100 text-theme-500 hover:bg-theme-200 inline-flex cursor-pointer items-center rounded-full px-2.5 py-0.5 text-xs font-medium"
@click.stop="removeFilter(f)"
>
Remove
</span>
<div
v-for="(f, i) in filters"
:key="i"
class="flex items-center justify-between space-x-2"
>
<InputRange
:model-value="f.percent"
@update:model-value="
updateFilters({ filter: f.filter, percent: $event })
"
></InputRange>
<div class="flex grow justify-between">
<span
class="bg-theme-500 text-theme-0 inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize"
>
{{ f.filter }}</span
>
<span
class="bg-theme-100 text-theme-500 hover:bg-theme-200 inline-flex cursor-pointer items-center rounded-full px-2.5 py-0.5 text-xs font-medium"
@click.stop="removeFilter(f)"
>
<div class="i-carbon-trash-can"></div>
</span>
</div>
</div>
</div>
</div>
<div class="border-theme-300 mt-4 rounded-md border p-4">
<div class="text-theme-300 mb-2 text-xs font-semibold uppercase">
Image Overlay
</div>
<InputOverlay></InputOverlay>
</div>
<div class="mt-4 text-center">
<ElButton btn="theme" size="sm" @click="vis = false"
>Done Editing</ElButton
>
<InputOverlay
:model-value="overlay"
@update:model-value="updateField('overlay', $event)"
></InputOverlay>
</div>
</div>
</div>
Expand All @@ -109,19 +118,19 @@
</template>
<script lang="ts" setup>
// @unocss-include
import { vue, FactorMedia } from "@factor/api"
import {
vue,
FactorMedia,
MediaDisplayObject,
getImageFilter,
imageFilters,
ImageFilter,
ImageFilterConfig,
} from "@factor/api"
OverlaySetting,
getGradientCss,
} from "./utils"
import ElModal from "./ElModal.vue"
import InputDropDown from "./InputDropDown.vue"
import InputOverlay from "./InputOverlay.vue"
import InputCheckbox from "./InputCheckbox.vue"
import InputRange from "./InputRange.vue"
import ElButton from "./ElButton.vue"
const vis = vue.ref()
Expand Down Expand Up @@ -160,6 +169,29 @@ const filters = vue.computed<ImageFilterConfig[]>(() => {
return editingItem.value?.filters || []
})
const overlay = vue.computed<OverlaySetting | undefined>(() => {
return editingItem.value?.overlay
})
const overlayStyle = vue.computed(() => {
const out: vue.StyleValue = {}
const ov = overlay.value
if (ov?.gradient?.stops?.length) {
out.opacity = (ov.opacity ?? 30) / 100
if (ov.gradient) {
out["background-image"] = getGradientCss(ov.gradient)
}
if (ov.blendMode) {
out.mixBlendMode = ov.blendMode as vue.CSSProperties["mixBlendMode"]
}
}
return out
})
const updateFilters = async (f: ImageFilterConfig) => {
const filtersValue = filters.value
Expand All @@ -181,9 +213,15 @@ const updateFilters = async (f: ImageFilterConfig) => {
}
}
const filterStyle = vue.computed(() => {
return filtersFull.value.map((f) => f.value).join(" ")
})
const updateField = async (field: string, value: unknown): Promise<void> => {
const v = props.modelValue
if (typeof editingIndex.value != "undefined") {
const existingValue = v[editingIndex.value]
const newValue = { ...existingValue, [field]: value }
v[editingIndex.value] = newValue
await updateValue(v)
}
}
const removeFilter = async (f: { filter: ImageFilter; percent?: number }) => {
const filtersValue = filters.value
Expand Down
3 changes: 2 additions & 1 deletion @factor/ui/InputMediaLibrary.vue
Expand Up @@ -46,7 +46,8 @@
</template>
<script lang="ts" setup>
// @unocss-include
import { vue, toLabel, FactorMedia, MediaDisplayObject } from "@factor/api"
import { vue, toLabel, FactorMedia } from "@factor/api"
import { MediaDisplayObject } from "./utils"
import ElModal from "./ElModal.vue"
import ElButton from "./ElButton.vue"
import ElSpinner from "./ElSpinner.vue"
Expand Down
9 changes: 2 additions & 7 deletions @factor/ui/InputMediaUpload.vue
Expand Up @@ -45,13 +45,8 @@
</div>
</template>
<script lang="ts" setup>
import {
vue,
FactorMedia,
MediaDisplayObject,
log,
objectId,
} from "@factor/api"
import { vue, FactorMedia, log, objectId } from "@factor/api"
import { MediaDisplayObject } from "./utils"
import ElSpinner from "./ElSpinner.vue"
import InputMediaEdit from "./InputMediaEdit.vue"
// uploadId is to allow label click without conflict with others on page
Expand Down
8 changes: 4 additions & 4 deletions @factor/ui/index.ts
Expand Up @@ -52,15 +52,15 @@ export class FactorUi extends FactorPlugin<FactorUiSettings> {
},
fontSize: {
"input-size": [
"var(--input-size)",
"var(--input-size, .875rem)",
{
lineHeight: "calc(var(--input-size) * 1.4)",
lineHeight: "calc(var(--input-size, .875rem) * 1.4)",
},
],
"input-label-size": [
"var(--input-label-size, .875rem)",
"var(--input-label-size, --input-size)",
{
lineHeight: "calc(var(--input-label-size) * 1.4)",
lineHeight: "calc(var(--input-label-size, --input-size) * 1.4)",
},
],
},
Expand Down

0 comments on commit c61f31d

Please sign in to comment.