Skip to content
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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Sidebar #685

wants to merge 2 commits into from

Conversation

antonmerkotun
Copy link

@antonmerkotun antonmerkotun commented Jan 30, 2025

Summary by CodeRabbit

Release Notes

  • Style

    • Refined code formatting across multiple Vue components
    • Improved template and script section readability
    • Consistent styling and indentation updates
  • Layout

    • Updated default layout to conditionally render Header, Navbar, and Sidebar
    • Enhanced sidebar navigation with dynamic content based on workspace state
  • UI Improvements

    • Added visual enhancements to various components with updated CSS classes
    • Simplified layout in some pages like forms/share

No functional changes were introduced in this release.

Copy link
Contributor

coderabbitai bot commented Jan 30, 2025

Walkthrough

This 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

File Change Summary
client/components/forms/* Minor template formatting and readability improvements
client/components/global/Header.vue New component with header section and centered content
client/components/global/SubSidebar.vue New component with navigation items and conditional rendering
client/layouts/default.vue Added conditional layout rendering based on route, new Sidebar and Header components
client/layouts/sidebar.vue New sidebar component with dynamic navigation items
client/pages/forms/[slug]/show.vue Restructured template, added RegenerateFormLink component, modified styling
client/pages/forms/[slug]/show/share.vue Simplified layout, commented out some components

Suggested Reviewers

  • JhumanJ

Poem

🐰 Code hops and skips with grace divine,
Formatting flows like a rabbit's design
Semicolons dance, templates align
Readability blooms, logic stays fine
A code garden pruned with rabbit's sign! 🌱


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?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 and restoreForm. One uses error.message while the other uses error.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:

  1. Implementing server-side pagination
  2. 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 custom max-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 and 219px) 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

📥 Commits

Reviewing files that changed from the base of the PR and between 932585b and 4336554.

⛔ 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 2

Length 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 2

Length 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:

  1. The pageCount constant (2) is intentionally hardcoded
  2. The total count calculation handles undefined workspaces correctly
client/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" />
Copy link
Contributor

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.

Suggested change
<slot class="flex-grow" />
<div class="flex-grow">
<slot />
</div>

Comment on lines +40 to +45
// {
// name: "Help Center",
// route: opnformConfig.links.help_url,
// params: { slug },
// iconPath: "/img/sidebar/help-center.svg",
// },
Copy link
Contributor

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",
-  // },

Comment on lines +28 to +184
<!-- <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>-->
Copy link
Contributor

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.

Comment on lines +4 to +9
<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>
Copy link
Contributor

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.

Suggested change
<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>

Comment on lines +32 to +39
<img
alt="icon"
:src="tab.iconPath"
:class="{
'filter-none': $route.name === tab.route,
grayscale: $route.name !== tab.route,
}"
>
Copy link
Contributor

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
};

Comment on lines +68 to +71
const props = defineProps({
tabsList: { type: Array, default: null },
isSubSidebar: { type: Boolean, default: false },
})
Copy link
Contributor

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.

Suggested change
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>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant