From 3819c97c640f135d97eba912a47d2c696e5b8601 Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Thu, 7 May 2026 17:18:59 +0600 Subject: [PATCH 1/4] Add side top/bottom placements & fixed-container positioning Introduce left-top/left-bottom and right-top/right-bottom placement variants across TS and PHP. Update RTL mapping and placement resolution so side sub-positions flip correctly, and extend calculatePosition with cases for the new placements. Add convertViewportPositionToContentPosition, getFixedContainingBlock and createsFixedContainingBlock helpers to account for scaled/fixed containing blocks when converting viewport coordinates to element coordinates. PHP Popover updated: add new position constants, include them in allowed placements and mapping, and fix placement class/attribute formatting. These changes improve positioning accuracy for popovers inside transformed or container-type elements and enable more granular side placements. --- assets/core/ts/components/popover.ts | 87 ++++++++++++++++++++++++++-- components/Constants/Positions.php | 4 ++ components/Popover.php | 28 +++++++-- 3 files changed, 109 insertions(+), 10 deletions(-) diff --git a/assets/core/ts/components/popover.ts b/assets/core/ts/components/popover.ts index caa91ee604..09b201b6fc 100644 --- a/assets/core/ts/components/popover.ts +++ b/assets/core/ts/components/popover.ts @@ -9,7 +9,11 @@ const PLACEMENTS = { BOTTOM_START: 'bottom-start', BOTTOM_END: 'bottom-end', LEFT: 'left', + LEFT_TOP: 'left-top', + LEFT_BOTTOM: 'left-bottom', RIGHT: 'right', + RIGHT_TOP: 'right-top', + RIGHT_BOTTOM: 'right-bottom', } as const; export interface PopoverProps { @@ -82,7 +86,11 @@ export const popover = (props: PopoverProps = {}) => ({ const rtlAdaptations: Record = { [PLACEMENTS.LEFT]: PLACEMENTS.RIGHT, + [PLACEMENTS.LEFT_TOP]: PLACEMENTS.RIGHT_TOP, + [PLACEMENTS.LEFT_BOTTOM]: PLACEMENTS.RIGHT_BOTTOM, [PLACEMENTS.RIGHT]: PLACEMENTS.LEFT, + [PLACEMENTS.RIGHT_TOP]: PLACEMENTS.LEFT_TOP, + [PLACEMENTS.RIGHT_BOTTOM]: PLACEMENTS.LEFT_BOTTOM, [PLACEMENTS.TOP_START]: PLACEMENTS.TOP_END, [PLACEMENTS.TOP_END]: PLACEMENTS.TOP_START, [PLACEMENTS.BOTTOM_START]: PLACEMENTS.BOTTOM_END, @@ -164,7 +172,8 @@ export const popover = (props: PopoverProps = {}) => ({ }; const placement = this.resolvePlacement(this.actualPlacement, triggerRect, contentRect, viewport); - const { top, left } = this.calculatePosition(triggerRect, contentRect, placement); + const viewportPosition = this.calculatePosition(triggerRect, contentRect, placement); + const { top, left } = this.convertViewportPositionToContentPosition(content, viewportPosition); // Apply positioning content.style.position = 'fixed'; @@ -207,12 +216,12 @@ export const popover = (props: PopoverProps = {}) => ({ return placement.replace('bottom', 'top'); } - if (placement === PLACEMENTS.LEFT && needsHorizontalFlip.left) { - return PLACEMENTS.RIGHT; + if (placement.startsWith('left') && needsHorizontalFlip.left) { + return placement.replace('left', 'right'); } - if (placement === PLACEMENTS.RIGHT && needsHorizontalFlip.right) { - return PLACEMENTS.LEFT; + if (placement.startsWith('right') && needsHorizontalFlip.right) { + return placement.replace('right', 'left'); } return placement; @@ -251,15 +260,83 @@ export const popover = (props: PopoverProps = {}) => ({ top = triggerRect.top + (triggerRect.height - contentRect.height) / 2; left = triggerRect.left - contentRect.width - this.offset; break; + case PLACEMENTS.LEFT_TOP: + top = triggerRect.top; + left = triggerRect.left - contentRect.width - this.offset; + break; + case PLACEMENTS.LEFT_BOTTOM: + top = triggerRect.bottom - contentRect.height; + left = triggerRect.left - contentRect.width - this.offset; + break; case PLACEMENTS.RIGHT: top = triggerRect.top + (triggerRect.height - contentRect.height) / 2; left = triggerRect.right + this.offset; break; + case PLACEMENTS.RIGHT_TOP: + top = triggerRect.top; + left = triggerRect.right + this.offset; + break; + case PLACEMENTS.RIGHT_BOTTOM: + top = triggerRect.bottom - contentRect.height; + left = triggerRect.right + this.offset; + break; } return { top, left }; }, + convertViewportPositionToContentPosition(content: HTMLElement, position: { top: number; left: number }) { + const containingBlock = this.getFixedContainingBlock(content); + + if (!containingBlock) { + return position; + } + + const containingBlockRect = containingBlock.getBoundingClientRect(); + const scaleX = containingBlock.offsetWidth ? containingBlockRect.width / containingBlock.offsetWidth || 1 : 1; + const scaleY = containingBlock.offsetHeight ? containingBlockRect.height / containingBlock.offsetHeight || 1 : 1; + + return { + top: (position.top - containingBlockRect.top) / scaleY - containingBlock.clientTop, + left: (position.left - containingBlockRect.left) / scaleX - containingBlock.clientLeft, + }; + }, + + getFixedContainingBlock(element: HTMLElement) { + let parent = element.parentElement; + + while (parent && parent !== document.documentElement) { + if (this.createsFixedContainingBlock(parent)) { + return parent; + } + + parent = parent.parentElement; + } + + return null; + }, + + createsFixedContainingBlock(element: HTMLElement) { + const style = window.getComputedStyle(element); + const willChangeProperties = style.willChange.split(',').map((property) => property.trim()); + const containProperties = style.contain.split(' '); + const backdropFilter = + style.getPropertyValue('backdrop-filter') || style.getPropertyValue('-webkit-backdrop-filter'); + const contentVisibility = style.getPropertyValue('content-visibility'); + const containerType = style.getPropertyValue('container-type'); + + return ( + style.transform !== 'none' || + style.perspective !== 'none' || + style.filter !== 'none' || + (backdropFilter !== '' && backdropFilter !== 'none') || + contentVisibility === 'auto' || + (containerType !== '' && containerType !== 'normal') || + willChangeProperties.some((property) => ['transform', 'perspective', 'filter'].includes(property)) || + containProperties.some((property) => ['layout', 'paint', 'strict', 'content'].includes(property)) + ); + }, + updatePlacementClasses(content: HTMLElement, placement: string) { // Remove all placement classes const placementClasses = ['tutor-popover-top', 'tutor-popover-bottom', 'tutor-popover-left', 'tutor-popover-right']; diff --git a/components/Constants/Positions.php b/components/Constants/Positions.php index 5f66898086..b645a5dbae 100644 --- a/components/Constants/Positions.php +++ b/components/Constants/Positions.php @@ -25,7 +25,11 @@ abstract class Positions { * @since 4.0.0 */ public const LEFT = 'left'; + public const LEFT_TOP = 'left-top'; + public const LEFT_BOTTOM = 'left-bottom'; public const RIGHT = 'right'; + public const RIGHT_TOP = 'right-top'; + public const RIGHT_BOTTOM = 'right-bottom'; public const TOP = 'top'; public const TOP_START = 'top-start'; public const TOP_END = 'top-end'; diff --git a/components/Popover.php b/components/Popover.php index 88725b77a4..ded0c71144 100644 --- a/components/Popover.php +++ b/components/Popover.php @@ -56,7 +56,11 @@ class Popover extends BaseComponent { Positions::BOTTOM_START => 'left.top', Positions::BOTTOM_END => 'right.top', Positions::LEFT => 'right.center', + Positions::LEFT_TOP => 'right.top', + Positions::LEFT_BOTTOM => 'right.bottom', Positions::RIGHT => 'left.center', + Positions::RIGHT_TOP => 'left.top', + Positions::RIGHT_BOTTOM => 'left.bottom', ); /** @@ -219,9 +223,23 @@ public function body( string $popover_body, array $allowed_html_tags = array() ) * @return self */ public function placement( string $popover_placement = 'bottom-start' ): self { - $placement_positions = array( Positions::TOP, Positions::LEFT, Positions::RIGHT, Positions::BOTTOM, Positions::BOTTOM_START, Positions::BOTTOM_END ); + $placement_positions = array( + Positions::TOP, + Positions::TOP_START, + Positions::TOP_END, + Positions::LEFT, + Positions::LEFT_TOP, + Positions::LEFT_BOTTOM, + Positions::RIGHT, + Positions::RIGHT_TOP, + Positions::RIGHT_BOTTOM, + Positions::BOTTOM, + Positions::BOTTOM_START, + Positions::BOTTOM_END, + ); if ( ! in_array( $popover_placement, $placement_positions, true ) ) { $this->popover_placement = Positions::BOTTOM_START; + return $this; } $this->popover_placement = $popover_placement; @@ -524,10 +542,10 @@ public function get(): string { $footer = $this->render_footer(); $menu = $this->render_menu(); - $placement_class = Positions::BOTTOM_START !== $placement_position ? "tutor-popover-$placement_position" : 'tutor-popover-top'; + $placement_class = 'tutor-popover-' . explode( '-', $placement_position )[0]; $class = 'tutor-popover ' . $placement_class; - $closeable_attr = $this->popover_close_outside ? '@click.outside="handleClickOutside()' : ''; + $closeable_attr = $this->popover_close_outside ? '@click.outside="handleClickOutside()"' : ''; $origin = self::TRANSFORM_ORIGIN_MAP[ $placement_position ] ?? 'center.top'; @@ -539,8 +557,8 @@ public function get(): string { x-show="open" x-cloak x-transition.%s - class=%s - %s" + class="%s" + %s > %s %s From 20640b870fe6fda4c13560d53d1a3bec7b51fa3e Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Thu, 7 May 2026 17:39:25 +0600 Subject: [PATCH 2/4] Add cover photo upload UI and handlers Introduce cover photo support and refactor user photo handling. Added a new camera SVG and registered the icon in types and Icon.php. Updated settings.ts to unify upload/remove endpoints (uploadUserPhoto/removeUserPhoto), add separate mutations/handlers for cover and profile photos, and pass photo_type with requests. Updated account.php template to render a cover photo uploader, reposition the avatar and provide dedicated controls for editing/removing cover and profile photos. Added SCSS for cover photo styling, loading states, and adjusted avatar visuals and positioning. --- assets/icons/camera.svg | 1 + .../js/frontend/dashboard/pages/settings.ts | 61 ++++++- assets/src/js/v3/shared/icons/types.ts | 1 + .../frontend/dashboard/settings/_account.scss | 65 ++++++-- classes/Icon.php | 1 + .../dashboard/account/settings/account.php | 155 +++++++++++++----- 6 files changed, 220 insertions(+), 64 deletions(-) create mode 100644 assets/icons/camera.svg diff --git a/assets/icons/camera.svg b/assets/icons/camera.svg new file mode 100644 index 0000000000..c63cf08286 --- /dev/null +++ b/assets/icons/camera.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/src/js/frontend/dashboard/pages/settings.ts b/assets/src/js/frontend/dashboard/pages/settings.ts index a317fc66b8..e22143ef67 100644 --- a/assets/src/js/frontend/dashboard/pages/settings.ts +++ b/assets/src/js/frontend/dashboard/pages/settings.ts @@ -7,9 +7,13 @@ import endpoints from '@TutorShared/utils/endpoints'; import { type TutorMutationResponse } from '@TutorShared/utils/types'; import { convertToErrorMessage } from '@TutorShared/utils/util'; -interface ProfilePhotoFormProps { +interface UserPhotoFormProps { photo_file: File; - photo_type: 'profile_photo'; + photo_type: 'profile_photo' | 'cover_photo'; +} + +interface RemoveUserPhotoProps { + photo_type: UserPhotoFormProps['photo_type']; } interface AccountFormProps { @@ -21,6 +25,8 @@ interface AccountFormProps { occupation: string; bio: string; display_name: string; + profile_photo: string; + cover_photo: string; tutor_pro_custom_signature_id: WPMedia | null; } @@ -89,6 +95,8 @@ const settings = () => { $el: null as HTMLElement | null, uploadProfilePhotoMutation: null as MutationState> | null, removeProfilePhotoMutation: null as MutationState> | null, + uploadCoverPhotoMutation: null as MutationState> | null, + removeCoverPhotoMutation: null as MutationState> | null, updateProfileMutation: null as MutationState> | null, saveSocialProfileMutation: null as MutationState> | null, saveBillingInfoMutation: null as MutationState> | null, @@ -106,6 +114,8 @@ const settings = () => { this.handleUpdateProfile = this.handleUpdateProfile.bind(this); this.handleUploadProfilePhoto = this.handleUploadProfilePhoto.bind(this); this.handleRemoveProfilePhoto = this.handleRemoveProfilePhoto.bind(this); + this.handleUploadCoverPhoto = this.handleUploadCoverPhoto.bind(this); + this.handleRemoveCoverPhoto = this.handleRemoveCoverPhoto.bind(this); this.handleSaveSocialProfile = this.handleSaveSocialProfile.bind(this); this.handleSaveBillingInfo = this.handleSaveBillingInfo.bind(this); this.handleSaveWithdrawMethod = this.handleSaveWithdrawMethod.bind(this); @@ -122,7 +132,7 @@ const settings = () => { }, }); - this.uploadProfilePhotoMutation = query.useMutation(this.uploadProfilePhoto, { + this.uploadProfilePhotoMutation = query.useMutation(this.uploadUserPhoto, { onSuccess: () => { toast.success(__('Successfully updated profile photo.', 'tutor')); }, @@ -131,7 +141,7 @@ const settings = () => { }, }); - this.removeProfilePhotoMutation = query.useMutation(this.removeProfilePhoto, { + this.removeProfilePhotoMutation = query.useMutation(this.removeUserPhoto, { onSuccess: () => { toast.success(__('Successfully removed profile photo.', 'tutor')); }, @@ -140,6 +150,24 @@ const settings = () => { }, }); + this.uploadCoverPhotoMutation = query.useMutation(this.uploadUserPhoto, { + onSuccess: () => { + toast.success(__('Successfully updated cover photo.', 'tutor')); + }, + onError: (error: Error) => { + toast.error(convertToErrorMessage(error)); + }, + }); + + this.removeCoverPhotoMutation = query.useMutation(this.removeUserPhoto, { + onSuccess: () => { + toast.success(__('Successfully removed cover photo.', 'tutor')); + }, + onError: (error: Error) => { + toast.error(convertToErrorMessage(error)); + }, + }); + this.updateProfileMutation = query.useMutation(this.updateProfile, { onSuccess: (data: TutorMutationResponse) => { toast.success(data?.message ?? __('Successfully updated profile', 'tutor')); @@ -271,7 +299,7 @@ const settings = () => { return wpAjaxInstance.post(endpoints.UPDATE_PROFILE_NOTIFICATION, transformedPayload).then((res) => res.data); }, - async uploadProfilePhoto(payload: ProfilePhotoFormProps) { + async uploadUserPhoto(payload: UserPhotoFormProps) { return wpAjaxInstance.post(endpoints.UPLOAD_PROFILE_PHOTO, payload).then((res) => res.data); }, @@ -282,16 +310,31 @@ const settings = () => { const data = { photo_file: files[0], photo_type: 'profile_photo', - } satisfies ProfilePhotoFormProps; + } satisfies UserPhotoFormProps; await this.uploadProfilePhotoMutation?.mutate(data); }, - async removeProfilePhoto() { - return wpAjaxInstance.post(endpoints.REMOVE_PROFILE_PHOTO).then((res) => res.data); + async handleUploadCoverPhoto(files: File[]) { + if (files.length === 0) { + return; + } + const data = { + photo_file: files[0], + photo_type: 'cover_photo', + } satisfies UserPhotoFormProps; + await this.uploadCoverPhotoMutation?.mutate(data); + }, + + async removeUserPhoto(payload: RemoveUserPhotoProps) { + return wpAjaxInstance.post(endpoints.REMOVE_PROFILE_PHOTO, payload).then((res) => res.data); }, async handleRemoveProfilePhoto() { - await this.removeProfilePhotoMutation?.mutate({}); + await this.removeProfilePhotoMutation?.mutate({ photo_type: 'profile_photo' }); + }, + + async handleRemoveCoverPhoto() { + await this.removeCoverPhotoMutation?.mutate({ photo_type: 'cover_photo' }); }, async updateProfile(payload: AccountFormProps) { diff --git a/assets/src/js/v3/shared/icons/types.ts b/assets/src/js/v3/shared/icons/types.ts index 0fc0ac5d20..a54bdbca3c 100644 --- a/assets/src/js/v3/shared/icons/types.ts +++ b/assets/src/js/v3/shared/icons/types.ts @@ -59,6 +59,7 @@ export const icons = [ 'calendarLine', 'calendarLines', 'callEnd', + 'camera', 'cart', 'categories', 'certificate', diff --git a/assets/src/scss/frontend/dashboard/settings/_account.scss b/assets/src/scss/frontend/dashboard/settings/_account.scss index 9646177b1d..348f78a411 100644 --- a/assets/src/scss/frontend/dashboard/settings/_account.scss +++ b/assets/src/scss/frontend/dashboard/settings/_account.scss @@ -2,18 +2,54 @@ @use '@Core/scss/tokens' as *; .tutor-account-section { + .tutor-account-cover-photo { + min-height: 184px; + border-radius: $tutor-radius-lg; + background-color: $tutor-surface-brand-quaternary; + background-position: center; + background-repeat: no-repeat; + background-size: cover; + position: relative; + + &.is-loading { + pointer-events: none; + background-image: none !important; + + & > * { + visibility: hidden; + } + + @include tutor-loading-spinner($tutor-surface-l1, $tutor-surface-l1-hover, 44px); + + &::before { + z-index: 1; + } + } + + .tutor-account-cover-photo-action { + position: absolute; + top: $tutor-spacing-4; + right: $tutor-spacing-4; + } + } + .tutor-account-avatar-wrapper { @include tutor-flex(row, center, center); - background-color: $tutor-surface-brand-tertiary; - border-radius: $tutor-radius-lg; - padding: $tutor-spacing-10; + transform: translateY(-52px); + margin-bottom: -52px; + position: relative; + z-index: $tutor-z-positive; .tutor-account-avatar { @include tutor-avatar-base(); width: 104px; height: 104px; - border: 2px solid $tutor-border-brand-secondary; - position: relative; + border: 4px solid $tutor-border-inverse; + overflow: visible; + + img { + border-radius: $tutor-radius-full; + } &.is-loading { position: relative; @@ -28,18 +64,17 @@ } .tutor-account-avatar-edit { - @include tutor-button-reset(); position: absolute; - inset: 0; - background-color: rgba($color: #000000, $alpha: 0.5); - color: $tutor-icon-idle-inverse; - display: none; - } + right: 0; + bottom: 0; + border: 3px solid $tutor-border-inverse; + border-radius: $tutor-radius-full; + @include tutor-transition((background-color, color)); - &.active, - &:hover { - .tutor-account-avatar-edit { - display: block; + &:hover, + &:focus, + &:active { + border: 3px solid $tutor-border-inverse; } } } diff --git a/classes/Icon.php b/classes/Icon.php index e254564307..3abeb94b37 100644 --- a/classes/Icon.php +++ b/classes/Icon.php @@ -75,6 +75,7 @@ final class Icon { const CALENDAR_LINE = 'calendar-line'; const CALENDAR_LINES = 'calendar-lines'; const CALL_END = 'call-end'; + const CAMERA = 'camera'; const CART = 'cart'; const CATEGORIES = 'categories'; const CERTIFICATE = 'certificate'; diff --git a/templates/dashboard/account/settings/account.php b/templates/dashboard/account/settings/account.php index 3186fa115e..304159a116 100644 --- a/templates/dashboard/account/settings/account.php +++ b/templates/dashboard/account/settings/account.php @@ -72,56 +72,51 @@ class="tutor-flex tutor-flex-column tutor-gap-6"
- +
+ + +
Date: Fri, 8 May 2026 10:42:13 +0600 Subject: [PATCH 3/4] Add medium tooltip size Introduce a medium tooltip variant across the codebase: add .tutor-tooltip-medium SCSS rules (max-width 226px, padding), add TOOLTIP_SIZES.MEDIUM and class handling in the tooltip TypeScript so the medium class is applied, and update the Tooltip PHP component to accept Size::MEDIUM and update the docblock. This ensures consistent frontend and backend support for a medium-sized tooltip. --- assets/core/scss/components/_tooltip.scss | 5 +++++ assets/core/ts/components/tooltip.ts | 7 +++++-- components/Tooltip.php | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/assets/core/scss/components/_tooltip.scss b/assets/core/scss/components/_tooltip.scss index a4d32d0b90..40144c1238 100644 --- a/assets/core/scss/components/_tooltip.scss +++ b/assets/core/scss/components/_tooltip.scss @@ -24,6 +24,11 @@ text-align: center; pointer-events: none; + &-medium { + max-width: 226px; + padding: $tutor-spacing-5; + } + &-large { max-width: 320px; padding: $tutor-spacing-5; diff --git a/assets/core/ts/components/tooltip.ts b/assets/core/ts/components/tooltip.ts index a074a6ed86..e632797574 100644 --- a/assets/core/ts/components/tooltip.ts +++ b/assets/core/ts/components/tooltip.ts @@ -18,6 +18,7 @@ const TOOLTIP_TRIGGERS = { const TOOLTIP_SIZES = { SMALL: 'small', + MEDIUM: 'medium', LARGE: 'large', } as const; @@ -328,14 +329,16 @@ export const tooltip = (props: TooltipProps = {}) => { 'tutor-tooltip-start', 'tutor-tooltip-end', ]; - const sizeClasses = ['tutor-tooltip-large']; + const sizeClasses = ['tutor-tooltip-medium', 'tutor-tooltip-large']; const arrowClasses = ['tutor-tooltip-arrow-start', 'tutor-tooltip-arrow-center', 'tutor-tooltip-arrow-end']; content.classList.remove(...placementClasses, ...sizeClasses, ...arrowClasses); content.classList.add(`tutor-tooltip-${placement}`); - if (this.size === TOOLTIP_SIZES.LARGE) { + if (this.size === TOOLTIP_SIZES.MEDIUM) { + content.classList.add('tutor-tooltip-medium'); + } else if (this.size === TOOLTIP_SIZES.LARGE) { content.classList.add('tutor-tooltip-large'); } diff --git a/components/Tooltip.php b/components/Tooltip.php index 22b8e4737f..7275a00cfd 100644 --- a/components/Tooltip.php +++ b/components/Tooltip.php @@ -71,7 +71,7 @@ class Tooltip extends BaseComponent { protected $placement = self::PLACEMENT_TOP; /** - * Tooltip size (small|large). + * Tooltip size (small|medium|large). * * @var string */ @@ -158,7 +158,7 @@ public function placement( string $placement ): self { * @return $this */ public function size( string $size ): self { - $allowed = array( Size::SMALL, Size::LARGE ); + $allowed = array( Size::SMALL, Size::MEDIUM, Size::LARGE ); if ( in_array( $size, $allowed, true ) ) { $this->size = $size; } From 68174419ff8835a7f52d3bb216f4ed4c4c132ae4 Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Fri, 8 May 2026 10:42:32 +0600 Subject: [PATCH 4/4] Refactor cover photo actions and add tooltip Rearrange the cover photo action markup to move the edit button outside the popover content and attach the Alpine popover behavior to the content block. Add a Tooltip component (imported Tutor\Components\Tooltip) that renders a small info button with profile/cover size guidance. Update SCSS for .tutor-account-cover-photo-action to use tutor-flex and add spacing (gap) so the action buttons align correctly. --- .../frontend/dashboard/settings/_account.scss | 2 + .../dashboard/account/settings/account.php | 100 +++++++++++------- 2 files changed, 62 insertions(+), 40 deletions(-) diff --git a/assets/src/scss/frontend/dashboard/settings/_account.scss b/assets/src/scss/frontend/dashboard/settings/_account.scss index 348f78a411..51e9efc1c2 100644 --- a/assets/src/scss/frontend/dashboard/settings/_account.scss +++ b/assets/src/scss/frontend/dashboard/settings/_account.scss @@ -27,6 +27,8 @@ } .tutor-account-cover-photo-action { + @include tutor-flex(); + gap: $tutor-spacing-3; position: absolute; top: $tutor-spacing-4; right: $tutor-spacing-4; diff --git a/templates/dashboard/account/settings/account.php b/templates/dashboard/account/settings/account.php index 304159a116..d62e07b88c 100644 --- a/templates/dashboard/account/settings/account.php +++ b/templates/dashboard/account/settings/account.php @@ -17,6 +17,7 @@ use Tutor\Components\Constants\Size; use Tutor\Components\Constants\Variant; use Tutor\Components\Constants\InputType; +use Tutor\Components\Tooltip; use Tutor\Components\WPEditor; $user = wp_get_current_user(); @@ -97,51 +98,70 @@ class="tutor-hidden" @change="handleFileSelect($event)" /> -