-
Notifications
You must be signed in to change notification settings - Fork 329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sidebar #685
base: main
Are you sure you want to change the base?
Sidebar #685
Conversation
WalkthroughThis pull request encompasses a comprehensive set of formatting and structural changes across multiple Vue components in the client directory. The modifications primarily focus on improving code readability, adjusting template structures, and making minor stylistic improvements. While most changes are cosmetic, some components like the default layout and sidebar have introduced new conditional rendering and navigation features. The changes do not significantly alter the functional behavior of the existing components. Changes
Suggested Reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🔭 Outside diff range comments (1)
client/components/pages/admin/DeletedForms.vue (1)
Line range hint
52-58
: Fix the API endpoint syntax.Remove the trailing comma after the URL in the
opnFetch
call.- opnFetch("/moderator/forms/" + props.user.id + "/deleted-forms",).then(data => { + opnFetch("/moderator/forms/" + props.user.id + "/deleted-forms").then(data => {
🧹 Nitpick comments (13)
client/components/pages/admin/DeletedForms.vue (3)
29-30
: LGTM! Consider extracting common styles.The pagination container styling looks good and follows Tailwind CSS conventions. However, if this styling pattern is used across multiple components, consider extracting it into a reusable class.
- class="flex justify-end px-3 py-3.5 border-t border-gray-200 dark:border-gray-700" + class="pagination-container"Add to your CSS:
.pagination-container { @apply flex justify-end px-3 py-3.5 border-t border-gray-200 dark:border-gray-700; }
Line range hint
52-58
: Standardize error handling across API calls.The error handling is inconsistent between
getDeletedForms
andrestoreForm
. One useserror.message
while the other useserror.data.message
.}).catch(error => { - useAlert().error(error.message) + useAlert().error(error.data?.message || error.message) loading.value = false }) // ... and in restoreForm ... }).catch(error => { restoringForm.value = false - useAlert().error(error.data.message) + useAlert().error(error.data?.message || error.message) })Also applies to: 67-77
Line range hint
41-49
: Optimize pagination implementation.The current pagination implementation loads all forms and slices them client-side. For better performance with large datasets, consider:
- Implementing server-side pagination
- Adding loading states for page changes
-const rows = computed(() => { - return forms.value.slice((page.value - 1) * pageCount, (page.value) * pageCount) -}) +const rows = computed(() => forms.value) + +watch(page, () => { + getDeletedForms() +}) + const getDeletedForms = () => { loading.value = true - opnFetch("/moderator/forms/" + props.user.id + "/deleted-forms").then(data => { + opnFetch("/moderator/forms/" + props.user.id + "/deleted-forms", { + params: { + page: page.value, + per_page: pageCount + } + }).then(data => {client/components/open/forms/components/ShareFormUrl.vue (1)
18-24
: Consider adding loading state to copy button.The button implementation could benefit from visual feedback during the copy operation.
<UButton class="shrink-0" size="sm" icon="i-heroicons-clipboard-document" label="Copy" + :loading="isCopying" @click="copyToClipboard" />
Add this to the script section:
const isCopying = ref(false) async function copyToClipboard() { if (import.meta.server) return isCopying.value = true try { await copy(share_url.value) if (props.form.visibility == 'draft') { useAlert().warning( 'Copied! But other people won\'t be able to see the form since it\'s currently in draft mode', ) } else { useAlert().success('Copied!') } } finally { isCopying.value = false } }client/layouts/default.vue (2)
2-2
: Consider using Tailwind's container class.The layout uses multiple utility classes. Consider using Tailwind's
container
class instead of setting a custommax-w-[1440px]
later in the template for consistent max-width handling across the app.- <div class="main-layout min-h-screen flex flex-col h-full"> + <div class="main-layout container min-h-screen flex flex-col h-full">
6-9
: Simplify conditional class binding.The dynamic class binding can be simplified by combining static and dynamic classes.
- <div - class="w-full mx-auto max-w-[1440px] h-full" - :class="{ flex: isFormsPage }" - > + <div class="w-full mx-auto max-w-[1440px] h-full" :class="isFormsPage && 'flex'">client/components/pages/admin/UserWorkspaces.vue (1)
6-12
: Consider adding error handling for the table component.The table configuration looks good, but it might benefit from error handling for failed data loading scenarios.
<UTable :loading-state="{ icon: 'i-heroicons-arrow-path-20-solid', label: 'Loading...' }" :progress="{ color: 'primary', animation: 'carousel' }" - :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'No items.' }" + :empty-state="{ + icon: 'i-heroicons-circle-stack-20-solid', + label: loading ? 'Loading...' : error ? 'Failed to load data.' : 'No items.' + }" :columns="columns" :rows="rows" class="-mx-6"client/layouts/sidebar.vue (1)
3-6
: Consider extracting width values to constants.The width values (
72px
and219px
) appear multiple times. Consider extracting them to constants for better maintainability.+<script setup lang="ts"> +const COLLAPSED_WIDTH = '72px' +const EXPANDED_WIDTH = '219px' +</script> <template> <main class="flex h-full"> <sub-sidebar - :class="[tabsList.length ? 'w-[72px]' : 'w-[219px]']" + :class="[tabsList.length ? `w-[${COLLAPSED_WIDTH}]` : `w-[${EXPANDED_WIDTH}]`]" :tabs-list="tabsMenuList" />client/pages/forms/[slug]/show.vue (1)
4-26
: Consider extracting the header section to a separate component.The header section with title, description, and actions could be extracted into a reusable component to improve maintainability and reusability.
+<!-- FormHeader.vue --> +<template> + <div class="flex items-end justify-between"> + <div class="flex flex-col gap-[6px]"> + <h3 class="font-medium text-[22px]">{{ title }}</h3> + <p>{{ description }}</p> + </div> + <div class="flex gap-3 items-center"> + <slot name="actions" /> + </div> + </div> +</template> <!-- show.vue --> - <div class="flex items-end justify-between"> - <div class="flex flex-col gap-[6px]"> - <h3 class="font-medium text-[22px]"> - Share - </h3> - <p>Manage your links to share it with others</p> - </div> - <div class="flex gap-3 items-center"> + <form-header + title="Share" + description="Manage your links to share it with others" + > + <template #actions> <regenerate-form-link v-if="!workspace.is_readonly" class="sm:w-1/2 flex !w-full" :form="form" /> <extra-menu v-if="!workspace.is_readonly" :form="form" /> - </div> - </div> + </template> + </form-header>client/components/global/Header.vue (2)
19-24
: Consider adding TypeScript interface for auth store user.The component uses TypeScript but doesn't type the
user
computed property. This could lead to type-safety issues.<script setup lang="ts"> import { computed } from "vue" +interface User { + // Add relevant user properties +} const authStore = useAuthStore() -const user = computed(() => authStore.user) +const user = computed((): User | null => authStore.user) </script>
10-14
: Consider making the header title configurable.The "Contact Form" text is hardcoded, which limits component reusability across different contexts.
+<script setup lang="ts"> +interface Props { + title?: string +} +defineProps<Props>() +</script> <template> <!-- ... --> <div class="px-6"> <p class="text-sm font-medium"> - Contact Form + {{ title || 'Contact Form' }} </p> </div>client/components/global/SubSidebar.vue (2)
8-17
: Avoid duplicate route definitions.The component has two separate
nuxt-link
elements pointing to 'forms-create'. Consider extracting this into a computed property or constant.+<script setup lang="ts"> +const createFormRoute = { + name: 'forms-create' +} as const; +</script> <template> <!-- Replace both instances of :to="{ name: 'forms-create' }" with --> - :to="{ name: 'forms-create' }" + :to="createFormRoute" </template>Also applies to: 52-62
23-31
: Simplify complex class bindings.The class binding logic is complex and could be simplified using computed properties.
+<script setup lang="ts"> +const getLinkClasses = computed(() => ({ + base: 'flex items-center transition-all duration-300 ease-in gap-3 rounded-lg hover:no-underline hover:bg-[#F6F8FA]', + layout: isSubSidebar ? 'p-2.5' : 'flex flex-col gap-2 w-12 py-2.5', + active: isSubSidebar ? 'text-blue-600 bg-[#F6F8FA]' : 'text-blue-600 bg-[#F6F8FA] border' +})) +</script> <template> <nuxt-link :to="{ name: tab.route, params: tab.params ?? {} }" - :class="isSubSidebar ? 'p-2.5' : 'flex flex-col gap-2 w-12 py-2.5'" - class="flex items-center transition-all duration-300 ease-in gap-3 rounded-lg hover:no-underline hover:bg-[#F6F8FA]" - :active-class=" - isSubSidebar - ? 'text-blue-600 bg-[#F6F8FA]' - : 'text-blue-600 bg-[#F6F8FA] border' - " + :class="[getLinkClasses.base, getLinkClasses.layout]" + :active-class="getLinkClasses.active" >
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (11)
client/package-lock.json
is excluded by!**/package-lock.json
client/public/img/sidebar/analytics.svg
is excluded by!**/*.svg
client/public/img/sidebar/dashboard.svg
is excluded by!**/*.svg
client/public/img/sidebar/help-center.svg
is excluded by!**/*.svg
client/public/img/sidebar/integrations.svg
is excluded by!**/*.svg
client/public/img/sidebar/plus.svg
is excluded by!**/*.svg
client/public/img/sidebar/search.svg
is excluded by!**/*.svg
client/public/img/sidebar/settings.svg
is excluded by!**/*.svg
client/public/img/sidebar/share.svg
is excluded by!**/*.svg
client/public/img/sidebar/submissions.svg
is excluded by!**/*.svg
client/public/img/sidebar/templates.svg
is excluded by!**/*.svg
📒 Files selected for processing (18)
client/components/forms/TextBlock.vue
(1 hunks)client/components/forms/components/MentionDropdown.vue
(1 hunks)client/components/forms/components/QuillyEditor.vue
(1 hunks)client/components/global/ErrorBoundary.vue
(1 hunks)client/components/global/Header.vue
(1 hunks)client/components/global/SubSidebar.vue
(1 hunks)client/components/open/forms/components/ShareFormUrl.vue
(1 hunks)client/components/open/forms/fields/components/MatrixPrefilledValues.vue
(1 hunks)client/components/pages/admin/DeletedForms.vue
(1 hunks)client/components/pages/admin/UserWorkspaces.vue
(2 hunks)client/components/pages/forms/show/EmbedCode.vue
(3 hunks)client/components/pages/forms/show/ShareLink.vue
(1 hunks)client/layouts/default.vue
(1 hunks)client/layouts/sidebar.vue
(1 hunks)client/pages/forms/[slug]/show.vue
(3 hunks)client/pages/forms/[slug]/show/share.vue
(1 hunks)client/pages/oauth/callback.vue
(1 hunks)client/pages/update-credentials.vue
(2 hunks)
✅ Files skipped from review due to trivial changes (10)
- client/components/pages/forms/show/ShareLink.vue
- client/components/global/ErrorBoundary.vue
- client/components/forms/TextBlock.vue
- client/components/forms/components/QuillyEditor.vue
- client/pages/forms/[slug]/show/share.vue
- client/pages/oauth/callback.vue
- client/components/pages/forms/show/EmbedCode.vue
- client/pages/update-credentials.vue
- client/components/open/forms/fields/components/MatrixPrefilledValues.vue
- client/components/forms/components/MentionDropdown.vue
🔇 Additional comments (6)
client/components/open/forms/components/ShareFormUrl.vue (3)
2-4
: LGTM! Well-structured container with proper dark mode support.The styling implementation effectively handles both light and dark themes while properly managing overflow cases.
26-27
: LGTM! Proper template structure.The template structure is well-formed with correct closing tags and indentation.
5-17
: Verify color contrast accessibility in dark mode.While the implementation is clean, let's ensure the text-nt-blue color provides sufficient contrast in dark mode for accessibility.
✅ Verification successful
Color contrast is sufficient for accessibility requirements
The text-nt-blue class uses Tailwind's blue-600 color, which provides adequate contrast ratios in both light and dark modes against their respective backgrounds. No additional dark mode adjustments are necessary.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for any custom color definitions that might affect text-nt-blue in dark mode rg -l "text-nt-blue|nt-blue" "client/assets" "client/tailwind.config" # Look for any existing a11y color utilities or overrides rg -l "\.dark.*text-nt-blue" "client/**/*.{vue,css}"Length of output: 301
Script:
#!/bin/bash # Find tailwind config file fd -t f "tailwind.config" # Search for color definitions and dark mode configuration rg -l "nt-blue|colors:|darkMode" # Look for any dark mode class usage with the blue color rg "dark:.*text-.*blue" -A 2 -B 2Length of output: 67611
Script:
#!/bin/bash # Check tailwind config content for color definitions and dark mode settings cat client/tailwind.config.js # Check for any dark mode color overrides in the codebase rg "text-nt-blue.*dark:" -A 2 -B 2Length of output: 2849
client/layouts/default.vue (1)
17-27
: LGTM! Clean and well-structured script setup.The script section is well-organized with clear imports and a focused computed property.
client/components/pages/admin/UserWorkspaces.vue (1)
23-32
: Verify pagination logic.The pagination implementation looks correct, but verify that:
- The
pageCount
constant (2) is intentionally hardcoded- The total count calculation handles undefined
workspaces
correctlyclient/pages/forms/[slug]/show.vue (1)
248-267
: LGTM! Clean route params format.The route params are consistently formatted without unnecessary quotes.
> | ||
<sidebar v-if="isFormsPage" /> | ||
|
||
<slot class="flex-grow" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Move flex-grow
class to the parent element.
The slot
element's class might not be applied as expected. Consider moving the flex-grow
class to a wrapper div.
- <slot class="flex-grow" />
+ <div class="flex-grow">
+ <slot />
+ </div>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<slot class="flex-grow" /> | |
<div class="flex-grow"> | |
<slot /> | |
</div> |
// { | ||
// name: "Help Center", | ||
// route: opnformConfig.links.help_url, | ||
// params: { slug }, | ||
// iconPath: "/img/sidebar/help-center.svg", | ||
// }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove commented code.
The commented-out help center navigation item should be removed if it's no longer needed.
- // {
- // name: "Help Center",
- // route: opnformConfig.links.help_url,
- // params: { slug },
- // iconPath: "/img/sidebar/help-center.svg",
- // },
<!-- <UButton--> | ||
<!-- v-if="!workspace.is_readonly"--> | ||
<!-- v-track.edit_form_click="{--> | ||
<!-- form_id: form.id,--> | ||
<!-- form_slug: form.slug,--> | ||
<!-- }"--> | ||
<!-- color="primary"--> | ||
<!-- icon="i-heroicons-pencil"--> | ||
<!-- class="hover:no-underline"--> | ||
<!-- :to="{ name: 'forms-slug-edit', params: { slug: form.slug } }"--> | ||
<!-- >--> | ||
<!-- Edit <span class="hidden md:inline">form</span>--> | ||
<!-- </UButton>--> | ||
<!-- <extra-menu v-if="!workspace.is_readonly" :form="form" />--> | ||
<!-- </div>--> | ||
<!-- </div>--> | ||
|
||
<!-- <p class="text-gray-500 text-sm">--> | ||
<!-- <span class="pr-1"--> | ||
<!-- >{{ form.views_count }} view{{--> | ||
<!-- form.views_count > 0 ? "s" : ""--> | ||
<!-- }}</span--> | ||
<!-- >--> | ||
<!-- <span class="pr-1"--> | ||
<!-- >- {{ form.submissions_count }} submission{{--> | ||
<!-- form.submissions_count > 0 ? "s" : ""--> | ||
<!-- }}--> | ||
<!-- </span>--> | ||
<!-- <span>- Edited {{ form.last_edited_human }}</span>--> | ||
<!-- </p>--> | ||
<!-- <div--> | ||
<!-- v-if="--> | ||
<!-- ['draft', 'closed'].includes(form.visibility) ||--> | ||
<!-- (form.tags && form.tags.length > 0)--> | ||
<!-- "--> | ||
<!-- class="mt-2 flex items-center flex-wrap gap-3"--> | ||
<!-- >--> | ||
<!-- <span--> | ||
<!-- v-if="form.visibility == 'draft'"--> | ||
<!-- class="inline-flex items-center rounded-full bg-yellow-100 px-2 py-1 text-xs font-medium text-yellow-600 ring-1 ring-inset ring-gray-500/10 dark:text-white dark:bg-gray-700"--> | ||
<!-- >--> | ||
<!-- Draft - not publicly accessible--> | ||
<!-- </span>--> | ||
<!-- <span--> | ||
<!-- v-else-if="form.visibility == 'closed'"--> | ||
<!-- class="inline-flex items-center rounded-full bg-yellow-100 px-2 py-1 text-xs font-medium text-yellow-600 ring-1 ring-inset ring-gray-500/10 dark:text-white dark:bg-gray-700"--> | ||
<!-- >--> | ||
<!-- Closed - won't accept new submissions--> | ||
<!-- </span>--> | ||
<!-- <span--> | ||
<!-- v-for="tag in form.tags"--> | ||
<!-- :key="tag"--> | ||
<!-- class="inline-flex items-center rounded-full bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:text-white dark:bg-gray-700"--> | ||
<!-- >--> | ||
<!-- {{ tag }}--> | ||
<!-- </span>--> | ||
<!-- </div>--> | ||
|
||
<!-- <p v-if="form.closes_at" class="text-yellow-500">--> | ||
<!-- <span v-if="form.is_closed">--> | ||
<!-- This form stopped accepting submissions on the--> | ||
<!-- {{ displayClosesDate }}--> | ||
<!-- </span>--> | ||
<!-- <span v-else>--> | ||
<!-- This form will stop accepting submissions on the--> | ||
<!-- {{ displayClosesDate }}--> | ||
<!-- </span>--> | ||
<!-- </p>--> | ||
<!-- <p v-if="form.max_submissions_count > 0" class="text-yellow-500">--> | ||
<!-- <span v-if="form.max_number_of_submissions_reached">--> | ||
<!-- The form is now closed because it reached its limit of--> | ||
<!-- {{ form.max_submissions_count }} submissions.--> | ||
<!-- </span>--> | ||
<!-- <span v-else>--> | ||
<!-- This form will stop accepting submissions after--> | ||
<!-- {{ form.max_submissions_count }} submissions.--> | ||
<!-- </span>--> | ||
<!-- </p>--> | ||
|
||
<!-- <form-cleanings class="mt-4" :form="form" />--> | ||
|
||
<!-- <div class="border-b border-gray-200 dark:border-gray-700">--> | ||
<!-- <ul class="flex flex-wrap -mb-px text-sm font-medium text-center">--> | ||
<!-- <li v-for="(tab, i) in tabsList" :key="i + 1" class="mr-6">--> | ||
<!-- <nuxt-link--> | ||
<!-- :to="{ name: tab.route, params: tab.params ?? {} }"--> | ||
<!-- class="hover:no-underline inline-block py-4 rounded-t-lg border-b-2 text-gray-500 hover:text-gray-600"--> | ||
<!-- active-class="text-blue-600 hover:text-blue-900 dark:text-blue-500 dark:hover:text-blue-500 border-blue-600 dark:border-blue-500"--> | ||
<!-- >--> | ||
<!-- {{ tab.name }}--> | ||
<!-- </nuxt-link>--> | ||
<!-- </li>--> | ||
<!-- </ul>--> | ||
<!-- </div>--> | ||
<!-- </div>--> | ||
<!-- </div>--> | ||
<!-- </div>--> | ||
<!-- <div class="flex flex-col bg-white">--> | ||
<!-- <NuxtPage :form="form" />--> | ||
<!-- </div>--> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove large block of commented code.
A significant portion of the template contains commented-out code. This should be removed to improve code maintainability. If this code needs to be preserved for reference, consider moving it to documentation or a separate branch.
<div class="h-full w-[72px] flex justify-center items-center border-r"> | ||
<button | ||
v-if="user" | ||
class="bg-[#1C1D35] rounded w-6 h-6" | ||
/> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add ARIA attributes for accessibility.
The button lacks purpose and accessibility attributes. Since it's conditionally rendered based on user state, it should clearly indicate its purpose.
<button
v-if="user"
+ aria-label="Toggle sidebar"
+ type="button"
class="bg-[#1C1D35] rounded w-6 h-6"
/>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<div class="h-full w-[72px] flex justify-center items-center border-r"> | |
<button | |
v-if="user" | |
class="bg-[#1C1D35] rounded w-6 h-6" | |
/> | |
</div> | |
<div class="h-full w-[72px] flex justify-center items-center border-r"> | |
<button | |
v-if="user" | |
aria-label="Toggle sidebar" | |
type="button" | |
class="bg-[#1C1D35] rounded w-6 h-6" | |
/> | |
</div> |
<img | ||
alt="icon" | ||
:src="tab.iconPath" | ||
:class="{ | ||
'filter-none': $route.name === tab.route, | ||
grayscale: $route.name !== tab.route, | ||
}" | ||
> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Handle image loading errors and improve accessibility.
The image elements lack error handling and proper accessibility attributes.
<img
alt="icon"
+ :alt="`${tab.name} icon`"
:src="tab.iconPath"
+ @error="handleImageError"
:class="{
'filter-none': $route.name === tab.route,
grayscale: $route.name !== tab.route,
}"
>
Add error handling:
const handleImageError = (e: Event) => {
const target = e.target as HTMLImageElement;
target.src = '/img/sidebar/default.svg'; // Fallback image
};
const props = defineProps({ | ||
tabsList: { type: Array, default: null }, | ||
isSubSidebar: { type: Boolean, default: false }, | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add TypeScript and proper prop validation.
The component would benefit from TypeScript interfaces and stricter prop validation.
-<script setup>
+<script setup lang="ts">
+interface Tab {
+ label: string
+ route: string
+ name: string
+ iconPath: string
+ params?: Record<string, unknown>
+}
+
+interface Props {
+ tabsList: Tab[] | null
+ isSubSidebar: boolean
+}
+
-const props = defineProps({
- tabsList: { type: Array, default: null },
- isSubSidebar: { type: Boolean, default: false },
-})
+const props = withDefaults(defineProps<Props>(), {
+ tabsList: null,
+ isSubSidebar: false
+})
</script>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const props = defineProps({ | |
tabsList: { type: Array, default: null }, | |
isSubSidebar: { type: Boolean, default: false }, | |
}) | |
<script setup lang="ts"> | |
interface Tab { | |
label: string | |
route: string | |
name: string | |
iconPath: string | |
params?: Record<string, unknown> | |
} | |
interface Props { | |
tabsList: Tab[] | null | |
isSubSidebar: boolean | |
} | |
const props = withDefaults(defineProps<Props>(), { | |
tabsList: null, | |
isSubSidebar: false | |
}) | |
</script> |
Summary by CodeRabbit
Release Notes
Style
Layout
Header
,Navbar
, andSidebar
UI Improvements
No functional changes were introduced in this release.