Skip to content
This repository has been archived by the owner on Dec 2, 2024. It is now read-only.

Commit

Permalink
feat: multi grid management (#496)
Browse files Browse the repository at this point in the history
  • Loading branch information
dzbo authored Oct 17, 2024
1 parent 61e1795 commit 8da33bc
Show file tree
Hide file tree
Showing 29 changed files with 904 additions and 87 deletions.
8 changes: 8 additions & 0 deletions app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const { cacheValue } = useCache()
const { currencyList } = storeToRefs(useCurrencyStore())
const { initProvider, reconnect } = useWalletConnectProvider()
const { formatMessage } = useIntl()
const { gridChainId, tempGridLayout } = storeToRefs(useGridStore())
const setupTranslations = () => {
useIntl().setupIntl(defaultConfig)
Expand Down Expand Up @@ -113,6 +114,13 @@ const setupNetwork = async () => {
if (SUPPORTED_NETWORK_IDS.includes(network)) {
selectedChainId.value = getNetworkById(network).chainId
// reset temp grid layout if network is changed
if (gridChainId.value !== selectedChainId.value) {
tempGridLayout.value = []
}
gridChainId.value = selectedChainId.value
await checkNetwork()
} else {
console.warn(
Expand Down
17 changes: 17 additions & 0 deletions components/AppModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,23 @@ watch(
},
{ deep: true, immediate: true }
)
const handleKeyDown = (event: KeyboardEvent) => {
const activeElement = document.activeElement?.tagName
const key = event.key
if (key === 'Escape' && activeElement === 'BODY') {
closeModal()
}
}
onMounted(() => {
document.addEventListener('keydown', handleKeyDown)
})
onUnmounted(() => {
document.removeEventListener('keydown', handleKeyDown)
})
</script>

<template>
Expand Down
117 changes: 117 additions & 0 deletions components/ModalTemplateAddEditGrid.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<script setup lang="ts">
import type { GridWidget } from '@/types/grid'
const { modal, closeModal } = useModal()
const { formatMessage } = useIntl()
const { tempGridLayout, selectedLayoutId } = storeToRefs(useGridStore())
const { addGrid, updateGrid } = useGrid()
const INPUT_FOCUS_DELAY = 10 // small delay for focusing input after element render
const DEFAULT_PROPERTIES = {
title: '',
}
const inputValues = reactive(DEFAULT_PROPERTIES)
const inputErrors = reactive({
title: '',
})
const id = computed(() => modal?.data?.grid?.id)
const canSubmit = ref(false)
const isEdit = computed(() => !!id.value)
const handleTitleChange = async (customEvent: CustomEvent) => {
const event = customEvent.detail.event
const input = event.target as HTMLInputElement
inputErrors.title = ''
if (!input.value) {
inputErrors.title = formatMessage('errors_required')
return
}
inputValues.title = input.value
}
const handleCancel = () => {
closeModal()
}
const handleSave = () => {
if (!canSubmit.value) {
return
}
const grid = toRaw(inputValues)
if (isEdit.value) {
updateGrid(id.value, {
...grid,
})
} else {
const newGrid: Grid<GridWidget> = {
id: createGridId<GridWidget>(grid, tempGridLayout.value),
title: grid.title,
grid: [],
}
addGrid(newGrid)
selectedLayoutId.value = newGrid.id
}
handleCancel()
}
watchEffect(() => {
canSubmit.value = !!inputValues.title && !inputErrors.title
})
onMounted(() => {
setTimeout(() => {
const input = document?.querySelector(
'lukso-input'
) as unknown as HTMLElement
input?.shadowRoot?.querySelector('input')?.focus()
}, INPUT_FOCUS_DELAY)
Object.assign(inputValues, modal?.data?.grid || DEFAULT_PROPERTIES)
})
</script>

<template>
<div class="p-6">
<div class="heading-inter-21-semi-bold pb-4">
{{ formatMessage(isEdit ? 'edit_grid_title' : 'add_grid_title') }}
</div>
<div class="paragraph-inter-14-regular pb-6">
{{
formatMessage(isEdit ? 'edit_grid_description' : 'add_grid_description')
}}
</div>

<lukso-input
.value="inputValues.title"
:placeholder="formatMessage('add_grid_title_placeholder')"
:error="inputErrors.title"
is-full-width
autofocus
@on-input="handleTitleChange"
></lukso-input>

<!-- Buttons -->
<div class="grid grid-cols-[max-content,auto] pt-6">
<lukso-button variant="text" @click="handleCancel">
{{ formatMessage('add_widget_cancel') }}
</lukso-button>
<lukso-button
:disabled="!canSubmit ? true : undefined"
variant="landing"
is-full-width
@click="handleSave"
>
{{ formatMessage('add_widget_confirm') }}
</lukso-button>
</div>
</div>
</template>
40 changes: 40 additions & 0 deletions components/ModalTemplateDeleteGrid.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<script setup lang="ts">
const { closeModal, modal } = useModal()
const { formatMessage } = useIntl()
const { removeGrid } = useGrid()
const handleDelete = async () => {
removeGrid(modal?.data?.id)
closeModal()
}
</script>

<template>
<div class="flex flex-col rounded-12 bg-neutral-98 p-6 text-center">
<div class="heading-inter-21-semi-bold pb-4">
{{ formatMessage('modal_delete_grid_title') }}
</div>
<div class="paragraph-inter-16-regular">
<lukso-sanitize
:html-content="
formatMessage('modal_delete_grid_content', {
title: `<strong>${modal?.data?.title}</strong>`,
})
"
></lukso-sanitize>
</div>
<div class="grid grid-cols-[max-content,auto]">
<lukso-button variant="text" @click="closeModal" class="mt-6">
{{ formatMessage('modal_delete_grid_cancel') }}
</lukso-button>
<lukso-button
variant="danger"
is-full-width
@click="handleDelete"
class="mt-6"
>
{{ formatMessage('modal_delete_grid_confirm') }}
</lukso-button>
</div>
</div>
</template>
98 changes: 98 additions & 0 deletions components/ModalTemplateMoveGridWidget.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script setup lang="ts">
import type { SelectStringOption } from '@lukso/web-components'
const { modal, closeModal } = useModal()
const { formatMessage } = useIntl()
const { tempGridLayout, selectedLayoutId } = storeToRefs(useGridStore())
const { addGridLayoutItem, removeGridLayoutItem, getGridById } = useGrid()
const selectedOption = ref<string>()
const canSubmit = computed(
() => selectedOption.value !== selectedLayoutId.value
)
const options = computed<SelectStringOption[]>(() => {
return tempGridLayout.value.map(grid => ({
id: grid.id,
value: grid.title,
}))
})
const selectedOptionValue = computed(() => {
const grid = tempGridLayout.value.find(
grid => grid.id === selectedOption.value
)
return {
id: grid?.id,
value: grid?.title,
}
})
const handleChange = async (customEvent: CustomEvent) => {
const option = customEvent.detail.value as SelectStringOption
selectedOption.value = option.id
}
const handleCancel = () => {
closeModal()
}
const handleSave = () => {
if (!canSubmit.value) {
return
}
const duplicatedWidget = createWidgetObject({
type: modal?.data?.type,
properties: modal?.data?.properties,
w: modal?.data?.w,
h: modal?.data?.h,
})
removeGridLayoutItem(modal?.data?.id)
addGridLayoutItem(
duplicatedWidget,
getGridById(tempGridLayout.value, selectedOption.value)
)
handleCancel()
}
onMounted(() => {
selectedOption.value = selectedLayoutId.value
})
</script>

<template>
<div class="p-6">
<div class="heading-inter-21-semi-bold pb-4">
{{ formatMessage('move_widget_title') }}
</div>
<div class="paragraph-inter-14-regular pb-6">
{{ formatMessage('move_widget_description') }}
</div>

<lukso-select
:value="JSON.stringify(selectedOptionValue)"
:options="JSON.stringify(options)"
is-full-width
autofocus
@on-select="handleChange"
></lukso-select>

<!-- Buttons -->
<div class="grid grid-cols-[max-content,auto] pt-6">
<lukso-button variant="text" @click="handleCancel">
{{ formatMessage('add_widget_cancel') }}
</lukso-button>
<lukso-button
:disabled="!canSubmit ? true : undefined"
variant="landing"
is-full-width
@click="handleSave"
>
{{ formatMessage('add_widget_confirm') }}
</lukso-button>
</div>
</div>
</template>
13 changes: 7 additions & 6 deletions components/ModalTemplateSwitchApplicationNetwork.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ const { closeModal, modal } = useModal()
const { formatMessage } = useIntl()
const handleChangeNetwork = async () => {
const { selectedChainId } = storeToRefs(useAppStore())
const { getNetworkByChainId } = useAppStore()
const { disconnect } = useBaseProvider()
selectedChainId.value = modal?.data?.chainId
await navigateTo({
path: homeRoute(),
query: { network: getNetworkByChainId(modal?.data?.chainId).id },
})
disconnect()
navigateTo(
{
path: homeRoute(),
query: { network: getNetworkByChainId(modal?.data?.chainId).id },
},
{ external: true }
)
}
</script>

Expand Down
2 changes: 1 addition & 1 deletion components/ProfileTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const handleToggleGridEditMode = async () => {
<lukso-icon
:name="isEditingGrid && isConnected ? 'close-lg' : 'edit'"
@click="handleToggleGridEditMode"
class="cursor-pointer transition hover:opacity-60"
class="cursor-pointer opacity-50 transition hover:opacity-100"
></lukso-icon>
</template>
</div>
Expand Down
2 changes: 1 addition & 1 deletion components/ProfileTabsItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const styleVariants = tv({
counter: 'bg-neutral-20 text-neutral-100',
},
false: {
tab: 'cursor-pointer opacity-50 transition hover:opacity-100 ',
tab: 'cursor-pointer opacity-50 transition hover:opacity-100',
counter: 'bg-transparent text-neutral-20',
},
},
Expand Down
2 changes: 2 additions & 0 deletions components/ProfileView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const assets = computed(() => assetsData.value || [])
const isLoadingAssets = computed(() =>
assets.value.some(asset => asset.isLoading)
)
const { gridCount } = useGrid()
const filteredAssets = computed(() => {
return (
Expand Down Expand Up @@ -86,6 +87,7 @@ const tabs = computed<ProfileViewTab[]>(() => {
return [
{
id: 'grid',
count: gridCount.value,
},
{
id: 'collectibles',
Expand Down
5 changes: 3 additions & 2 deletions domains/grid/components/AddWidgetBasic.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ type Props = {
const props = defineProps<Props>()
const { formatMessage } = useIntl()
const { closeModal, showModal } = useModal()
const { addGridLayoutItem, updateGridLayoutItem } = useGrid()
const { addGridLayoutItem, updateGridLayoutItem, getSelectedLayout } = useGrid()
const { tempGridLayout } = storeToRefs(useGridStore())
const TEXTAREA_FOCUS_DELAY = 10 // small delay for focusing textarea after element render
const inputValue = ref('')
Expand Down Expand Up @@ -42,7 +43,7 @@ const handleSave = () => {
h: props.height,
})
addGridLayoutItem(newWidget)
addGridLayoutItem(newWidget, getSelectedLayout(tempGridLayout.value))
}
handleCancel()
Expand Down
5 changes: 3 additions & 2 deletions domains/grid/components/AddWidgetGenericPlatform.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ type Props = {
const props = defineProps<Props>()
const { formatMessage } = useIntl()
const { closeModal, showModal } = useModal()
const { addGridLayoutItem, updateGridLayoutItem } = useGrid()
const { addGridLayoutItem, updateGridLayoutItem, getSelectedLayout } = useGrid()
const { tempGridLayout } = storeToRefs(useGridStore())
const TEXTAREA_FOCUS_DELAY = 10 // small delay for focusing textarea after element render
const inputValue = ref('')
Expand Down Expand Up @@ -44,7 +45,7 @@ const handleSave = async () => {
h: props.height,
})
addGridLayoutItem(newWidget)
addGridLayoutItem(newWidget, getSelectedLayout(tempGridLayout.value))
}
handleCancel()
Expand Down
Loading

0 comments on commit 8da33bc

Please sign in to comment.