Skip to content

Commit

Permalink
feat(button-modal): add loading backdrop feature and menu items mock …
Browse files Browse the repository at this point in the history
…data (#5214)

* feat(icons): rename and add new service-related icons for clarity

Signed-off-by: Wanjin Noh <[email protected]>

* feat(editor): update drop image plugin to set node markup correctly

Signed-off-by: Wanjin Noh <[email protected]>

* feat(context-menu): improve selection handling in PContextMenu component

Signed-off-by: Wanjin Noh <[email protected]>

* feat(button-modal): add loading backdrop feature and menu items mock data

Signed-off-by: Wanjin Noh <[email protected]>

* feat(user-select-dropdown): enhance user label resolution and sorting logic

Signed-off-by: Wanjin Noh <[email protected]>

* feat: add internationalization support for edit and delete buttons

Signed-off-by: Wanjin Noh <[email protected]>

---------

Signed-off-by: Wanjin Noh <[email protected]>
  • Loading branch information
WANZARGEN authored Dec 12, 2024
1 parent e435d2a commit eefd872
Show file tree
Hide file tree
Showing 21 changed files with 954 additions and 71 deletions.
10 changes: 6 additions & 4 deletions apps/web/src/common/components/buttons/ActionMenuButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ref, computed } from 'vue';
import { PIconButton, PContextMenu, useContextMenuStyle } from '@cloudforet/mirinae';
import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/type';
import { i18n } from '@/translations';
interface ActionMenuItem extends MenuItem {
name: string;
}
Expand Down Expand Up @@ -37,8 +39,8 @@ useContextMenuStyle({
menuWidth: props.size === 'sm' ? '113px' : '192px',
});
const menuMap = computed<Record<SupportMenu, ActionMenuItem>>(() => ({
edit: { name: 'edit', icon: 'ic_edit', label: 'Edit' },
delete: { name: 'delete', icon: 'ic_delete', label: 'Delete' },
edit: { name: 'edit', icon: 'ic_edit', label: i18n.t('COMMON.BUTTONS.EDIT') },
delete: { name: 'delete', icon: 'ic_delete', label: i18n.t('COMMON.BUTTONS.DELETE') },
}));
const menu = computed<ActionMenuItem[]>(() => {
if (props.menu) {
Expand All @@ -50,8 +52,8 @@ const menu = computed<ActionMenuItem[]>(() => {
});
}
return [
{ name: 'edit', icon: 'ic_edit', label: 'Edit' },
{ name: 'delete', icon: 'ic_delete', label: 'Delete' },
{ name: 'edit', icon: 'ic_edit', label: i18n.t('COMMON.BUTTONS.EDIT') },
{ name: 'delete', icon: 'ic_delete', label: i18n.t('COMMON.BUTTONS.DELETE') },
];
});
const toggleMenu = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ export const dropImagePlugin = (upload: ImageUploader<any>, imgFileDataMap: Map<
src: downloadUrl,
'file-id': fileId,
});
// const transaction = view.state.tr.insert(coordinates.pos, node);
const transaction = view.state.tr.setNodeMarkup(coordinates.pos, schema.nodes.image, node.attrs);
const loadingPos = view.state.selection.anchor - 1; // get the position of the loading node
const transaction = view.state.tr.setNodeMarkup(loadingPos, schema.nodes.image, node.attrs);
view.dispatch(transaction);
} else {
reader.onload = (readerEvent) => {
Expand Down
7 changes: 4 additions & 3 deletions apps/web/src/common/modules/user/UserSelectDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ const allUserItems = computed<UserDropdownItem[]>(() => {
if (props.userPool && props.userPool.length > 0) {
return props.userPool.map((userId) => ({
name: userId,
label: userReferenceMap.value[userId]?.label ?? userId,
label: userReferenceMap.value[userId]?.label || userReferenceMap.value[userId]?.name || userId,
}));
}
return Object.values(userReferenceMap.value).map((u: UserReferenceMap[string]) => ({
name: u.key,
label: u.label,
}));
label: u.label || u.name || u.key,
})).sort((a, b) => a.label.localeCompare(b.label));
});
const selectedUserItems = ref<SelectDropdownMenuItem[]>([]);
const userMenuItemsHandler: AutocompleteHandler = async (keyword: string, pageStart = 1, pageLimit = 10) => {
Expand Down Expand Up @@ -125,6 +125,7 @@ watch([loading, () => props.userId, () => props.userIds], ([_loading, newUserId,
<p-select-dropdown show-select-marker
:selected="selectedUserItems"
:handler="userMenuItemsHandler"
:page-size="10"
is-filterable
:invalid="props.invalid"
:disabled="props.disabled"
Expand Down
723 changes: 723 additions & 0 deletions packages/language-pack/console-translation-2.8.babel

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions packages/language-pack/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -702,8 +702,11 @@
"BUTTONS": {
"ADD": "Add",
"CANCEL": "Cancel",
"CONFIRM": "Confirm",
"DELETE": "Delete",
"DONE": "Done",
"DOWNLOAD": "Download",
"EDIT": "Edit",
"PDF_DOWNLOAD_BUTTON": {
"DESKTOP": "desktop",
"SUPPORT_PDF_HELP_TEXT": "This feature is not supported on your browser or device. Try again with {chrome} or {edge} browser on {desktop}."
Expand Down
3 changes: 3 additions & 0 deletions packages/language-pack/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -702,8 +702,11 @@
"BUTTONS": {
"ADD": "追加",
"CANCEL": "キャンセル",
"CONFIRM": "",
"DELETE": "",
"DONE": "完了",
"DOWNLOAD": "ダウンロード",
"EDIT": "",
"PDF_DOWNLOAD_BUTTON": {
"DESKTOP": "デスクトップ",
"SUPPORT_PDF_HELP_TEXT": "この機能は、ご使用のブラウザまたはデバイスではサポートされていません。 {desktop}で{chrome}または{edge}ブラウザを使用して再試行してください。"
Expand Down
3 changes: 3 additions & 0 deletions packages/language-pack/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -702,8 +702,11 @@
"BUTTONS": {
"ADD": "추가",
"CANCEL": "취소",
"CONFIRM": "확인",
"DELETE": "삭제",
"DONE": "완료",
"DOWNLOAD": "다운로드",
"EDIT": "수정",
"PDF_DOWNLOAD_BUTTON": {
"DESKTOP": "데스크탑",
"SUPPORT_PDF_HELP_TEXT": "해당 기능을 지원하지 않는 브라우저 또는 디바이스입니다. {desktop} 환경의 {chrome} 또는 {edge} 브라우저에서 이용해주세요."
Expand Down
9 changes: 5 additions & 4 deletions packages/mirinae/src/controls/context-menu/PContextMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,9 @@ const onClickMenu = (item: MenuItem, index) => {
if (props.multiSelectable) {
if (state.selectedNameMap[item.name ?? ''] !== undefined) {
const indexOfSelected = state.selectedNameMap[item.name ?? ''];
state.proxySelected.splice(indexOfSelected, 1);
state.proxySelected = [...state.proxySelected];
const newSelected = [...state.proxySelected];
newSelected.splice(indexOfSelected, 1);
state.proxySelected = newSelected;
} else {
state.proxySelected = [...state.proxySelected, item];
}
Expand Down Expand Up @@ -274,8 +275,8 @@ defineExpose({
:ellipsis="props.itemHeightFixed"
:highlight-term="state.proxySearchText || props.highlightTerm"
:tabindex="readonly ? -1 : index"
@click.stop.prevent="readonly ? undefined : onClickMenu(item, index, $event)"
@keyup.enter="readonly ? undefined : onClickMenu(item, index, $event)"
@click.stop.prevent="onClickMenu(item, index, $event)"
@keyup.enter="onClickMenu(item, index, $event)"
@keydown.up="onKeyUp(index)"
@keydown.down="onKeyDown(index)"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ import * as PButtonModalStories from './PButtonModal.stories';
<br/>
<br/>

## Basic
<Canvas of={PButtonModalStories.Basic} />

<br/>
<br/>

## Loading Backdrop
<Canvas of={PButtonModalStories.LoadingBackdrop} />

<br/>
<br/>

## Playground
<Canvas of={PButtonModalStories.Playground} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { ComponentProps } from 'vue-component-type-helpers';

import PButton from '@/controls/buttons/button/PButton.vue';
import PSelectDropdown from '@/controls/dropdown/select-dropdown/PSelectDropdown.vue';
import { getMenuItems } from '@/feedbacks/modals/button-modal/mock';
import PButtonModal from '@/feedbacks/modals/button-modal/PButtonModal.vue';
import { getButtonModalArgs, getButtonModalArgTypes, getButtonModalParameters } from '@/feedbacks/modals/button-modal/story-helper';

Expand Down Expand Up @@ -54,6 +55,7 @@ const Template: Story = {
:hide-footer-confirm-button="hideFooterConfirmButton"
:footer-reset-button-visible="footerResetButtonVisible"
:loading="loading"
:loading-backdrop="loadingBackdrop"
:disabled="disabled"
:absolute="absolute"
:modal-body-id="modalBodyId"
Expand All @@ -75,62 +77,7 @@ const Template: Story = {
const state = reactive({
modalVisible: props.visible,
contents: computed(() => faker.lorem.lines(props.contentsHeight)),
menu: [
{
type: 'item', label: 'Add', name: 'add', disabled: false,
},
{
type: 'item', label: 'Hello', name: 'hello', disabled: false,
},
{ type: 'divider' },
{ type: 'header', label: 'this is header' },
{
type: 'item', label: 'Update', name: 'update', disabled: false,
},
{
type: 'item', label: 'Delete', name: 'delete', disabled: false,
},
{ type: 'divider' },
{
type: 'item', label: 'Collect', name: 'collect', disabled: false,
},
{ type: 'divider' },
{
type: 'item', label: 'Remove', name: 'remove', disabled: true,
},
],
items: [
{ type: 'item', label: 'one', name: 'one' },
{ type: 'item', label: 'two', name: 'two' },
{ type: 'item', label: 'three', name: 'three' },
{ type: 'item', label: 'four', name: 'four' },
{ type: 'item', label: 'five', name: 'five' },
{ type: 'item', label: 'six', name: 'six' },
{ type: 'item', label: 'one', name: 'one' },
{ type: 'item', label: 'two', name: 'two' },
{ type: 'item', label: 'three', name: 'three' },
{ type: 'item', label: 'four', name: 'four' },
{ type: 'item', label: 'five', name: 'five' },
{ type: 'item', label: 'six', name: 'six' },
{ type: 'item', label: 'one', name: 'one' },
{ type: 'item', label: 'two', name: 'two' },
{ type: 'item', label: 'three', name: 'three' },
{ type: 'item', label: 'four', name: 'four' },
{ type: 'item', label: 'five', name: 'five' },
{ type: 'item', label: 'six', name: 'six' },
{ type: 'item', label: 'one', name: 'one' },
{ type: 'item', label: 'two', name: 'two' },
{ type: 'item', label: 'three', name: 'three' },
{ type: 'item', label: 'four', name: 'four' },
{ type: 'item', label: 'five', name: 'five' },
{ type: 'item', label: 'six', name: 'six' },
{ type: 'item', label: 'one', name: 'one' },
{ type: 'item', label: 'two', name: 'two' },
{ type: 'item', label: 'three', name: 'three' },
{ type: 'item', label: 'four', name: 'four' },
{ type: 'item', label: 'five', name: 'five' },
{ type: 'item', label: 'six', name: 'six' },
],
items: getMenuItems(),
});
const launchModal = () => {
state.modalVisible = true;
Expand All @@ -148,6 +95,80 @@ const Template: Story = {
}),
};


export const Basic: Story = {
render: () => ({
components: { PButtonModal, PButton },
template: `
<div>
<p-button @click="modalVisible = true">Launch a modal</p-button>
<p-button-modal :visible.sync="modalVisible"
@confirm="handleConfirm"
>
<template #body>
<p>{{ contents }}</p>
</template>
</p-button-modal>
</div>
`,
setup() {
const state = reactive({
modalVisible: false,
contents: computed(() => faker.lorem.lines(5)),
});
const handleConfirm = () => {
state.modalVisible = false;
};
return {
...toRefs(state),
handleConfirm,
};
},
}),
};

export const LoadingBackdrop: Story = {
render: () => ({
components: { PButtonModal, PButton },
template: `
<div>
<p-button @click="launchModal">Launch a modal</p-button>
<p-button-modal :visible.sync="modalVisible"
:loading-backdrop="loadingBackdrop"
@confirm="handleConfirm"
>
<template #body>
<p>{{ contents }}</p>
</template>
</p-button-modal>
</div>
`,
setup() {
const state = reactive({
modalVisible: false,
contents: computed(() => faker.lorem.lines(5)),
loadingBackdrop: true,
});

const launchModal = () => {
state.loadingBackdrop = true;
state.modalVisible = true;
setTimeout(() => {
state.loadingBackdrop = false;
}, 3000);
};
const handleConfirm = () => {
state.modalVisible = false;
};
return {
...toRefs(state),
launchModal,
handleConfirm,
};
},
}),
};

export const Playground: Story = {
...Template,
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@
@after-leave="onModalLeave"
>
<div class="modal-mask"
:class="[{'no-backdrop':!backdrop}, {'absolute': !!absolute}]"
:class="[{'no-backdrop':!backdrop}, {
'absolute': !!absolute,
'loading-backdrop': loadingBackdrop
}]"
:style="absolute ? [{'top': `${absolute}rem`}, {'left': `${absolute}rem`}] : {}"
>
<div class="modal-wrapper"
<p-spinner v-if="loadingBackdrop"
size="xl"
style-type="white"
/>
<div v-if="!loadingBackdrop"
class="modal-wrapper"
:class="dialogClassObject"
role="dialog"
aria-modal="true"
Expand Down Expand Up @@ -115,6 +123,7 @@ import type { TranslateResult } from 'vue-i18n';
import PButton from '@/controls/buttons/button/PButton.vue';
import { BUTTON_STYLE } from '@/controls/buttons/button/type';
import PIconButton from '@/controls/buttons/icon-button/PIconButton.vue';
import PSpinner from '@/feedbacks/loading/spinner/PSpinner.vue';
import type { ButtonModalProps } from '@/feedbacks/modals/button-modal/type';
import { THEME_COLORS } from '@/feedbacks/modals/button-modal/type';
import { SizeMapping } from '@/feedbacks/modals/type';
Expand All @@ -127,6 +136,7 @@ import { useProxyValue } from '@/hooks';
export default defineComponent<ButtonModalProps>({
name: 'PButtonModal',
components: {
PSpinner,
PI,
PIconButton,
PButton,
Expand Down Expand Up @@ -204,6 +214,10 @@ export default defineComponent<ButtonModalProps>({
type: String,
default: undefined,
},
loadingBackdrop: {
type: Boolean,
default: false,
},
},
setup(props, { emit }) {
const state = reactive({
Expand Down
34 changes: 34 additions & 0 deletions packages/mirinae/src/feedbacks/modals/button-modal/mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { MenuItem } from '@/controls/context-menu/type';

export const getMenuItems = (): MenuItem[] => [
{ type: 'item', label: 'one', name: 'one' },
{ type: 'item', label: 'two', name: 'two' },
{ type: 'item', label: 'three', name: 'three' },
{ type: 'item', label: 'four', name: 'four' },
{ type: 'item', label: 'five', name: 'five' },
{ type: 'item', label: 'six', name: 'six' },
{ type: 'item', label: 'one', name: 'one' },
{ type: 'item', label: 'two', name: 'two' },
{ type: 'item', label: 'three', name: 'three' },
{ type: 'item', label: 'four', name: 'four' },
{ type: 'item', label: 'five', name: 'five' },
{ type: 'item', label: 'six', name: 'six' },
{ type: 'item', label: 'one', name: 'one' },
{ type: 'item', label: 'two', name: 'two' },
{ type: 'item', label: 'three', name: 'three' },
{ type: 'item', label: 'four', name: 'four' },
{ type: 'item', label: 'five', name: 'five' },
{ type: 'item', label: 'six', name: 'six' },
{ type: 'item', label: 'one', name: 'one' },
{ type: 'item', label: 'two', name: 'two' },
{ type: 'item', label: 'three', name: 'three' },
{ type: 'item', label: 'four', name: 'four' },
{ type: 'item', label: 'five', name: 'five' },
{ type: 'item', label: 'six', name: 'six' },
{ type: 'item', label: 'one', name: 'one' },
{ type: 'item', label: 'two', name: 'two' },
{ type: 'item', label: 'three', name: 'three' },
{ type: 'item', label: 'four', name: 'four' },
{ type: 'item', label: 'five', name: 'five' },
{ type: 'item', label: 'six', name: 'six' },
];
Loading

0 comments on commit eefd872

Please sign in to comment.