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

feat: add kitchen sink example #281

Merged
merged 2 commits into from
Oct 3, 2024
Merged

Conversation

MartianGreed
Copy link
Collaborator

@MartianGreed MartianGreed commented Sep 26, 2024

Closes #

Introduced changes

Checklist

  • Linked relevant issue
  • Updated relevant documentation
  • Added relevant tests
  • Add a dedicated CI job for new examples
  • Performed self-review of the code

Summary by CodeRabbit

  • New Features

    • Introduced a new submodule for "onchain-dash" to enhance project capabilities.
    • Added a comprehensive set of files for a Vite-based React application, including environment configuration and project setup.
    • Implemented multiple new UI components, including CallerCounter, Chat, GlobalCounter, Header, Sidebar, StarknetProvider, ThemeSwitchButton, and various reusable UI elements.
  • Documentation

    • Added a README file with detailed setup instructions and project information.
  • Chores

    • Configured ESLint and PostCSS for better development practices.
    • Set up Tailwind CSS for styling and theming support.
    • Established TypeScript and Vite configurations for improved project structure and performance.
    • Updated .gitignore to exclude local Netlify folder.

Copy link

coderabbitai bot commented Sep 26, 2024

Walkthrough

The pull request introduces a new submodule for "onchain-dash" and a comprehensive set of files for a Vite-based React application. Key additions include configuration files, components, and a README, establishing a modern development environment with Tailwind CSS and the Dojo Engine. The existing submodule remains unchanged, while new files support the on-chain dashboard project. Additionally, the .gitignore file has been updated to exclude the local Netlify folder.

Changes

Files Change Summary
.gitmodules Added new submodule onchain-dash with path worlds/onchain-dash and URL https://github.com/MartianGreed/onchain-dash. Duplicate entry for the same submodule also added.
.gitignore Updated to include .netlify in the list of ignored files and added a newline for formatting.
examples/example-vite-kitchen-sink Introduced various files for a Vite-based React application, including configuration, components, and styles. New components and interfaces added, along with functions and constants for enhanced functionality.
examples/example-vite-kitchen-sink/.env.dist Added environment variables for the application, defining RPC URLs and API keys.
examples/example-vite-kitchen-sink/.eslintrc.json Introduced ESLint configuration extending Next.js rules for TypeScript.
examples/example-vite-kitchen-sink/.gitignore Specified files and directories to be ignored by Git.
examples/example-vite-kitchen-sink/README.md Provided instructions for getting started with the project and running the development server.
examples/example-vite-kitchen-sink/components.json Configured settings for the Shadcn UI framework.
examples/example-vite-kitchen-sink/index.html Main HTML entry point for the Vite application.
examples/example-vite-kitchen-sink/package.json Defined project dependencies, scripts, and metadata.
examples/example-vite-kitchen-sink/postcss.config.mjs Configured PostCSS to use the Tailwind CSS plugin.
examples/example-vite-kitchen-sink/src/app/globals.css Established base styles and utilities using Tailwind CSS.
examples/example-vite-kitchen-sink/src/app/layout.tsx Defined the RootLayout component to integrate providers and UI elements.
examples/example-vite-kitchen-sink/src/app/page.tsx Implemented the Home component for the dashboard interface.
examples/example-vite-kitchen-sink/src/components/ Introduced various UI components for the application, including counters, chat, headers, and sidebars.
examples/example-vite-kitchen-sink/src/dojo/ Defined Dojo Engine configuration and schema for the on-chain dashboard.
examples/example-vite-kitchen-sink/src/env.ts Set up environment variables and exported a function for constructing RPC URLs.
examples/example-vite-kitchen-sink/src/lib/utils.ts Added utility functions for class name management and value handling.
examples/example-vite-kitchen-sink/src/main.tsx Initialized the React application using the React 18 API.
examples/example-vite-kitchen-sink/tailwind.config.ts Configured Tailwind CSS settings, including dark mode and theme extensions.
examples/example-vite-kitchen-sink/tsconfig.json Specified TypeScript compiler options for the project.
examples/example-vite-kitchen-sink/vite.config.ts Set up Vite project configuration with necessary plugins.

Possibly related PRs

  • fix: prettier #277: The changes in this PR involve restructuring the database connection initialization using the Dojo Engine SDK, which is relevant to the new submodule "onchain-dash" that likely utilizes similar database functionalities.

Poem

In a garden of code, where the bunnies play,
New modules sprout, brightening the day.
With Vite and React, we hop and we cheer,
Tailwind and Dojo, our vision is clear!
So let’s build our dreams, with joy and delight,
In this wondrous code world, everything feels right! 🐇✨


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

@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: 39

🧹 Outside diff range and nitpick comments (65)
examples/example-vite-kitchen-sink/postcss.config.mjs (1)

2-6: Configuration looks good, consider additional plugins if needed

The PostCSS configuration is correctly structured and includes Tailwind CSS, which is an excellent choice for a utility-first CSS framework. The empty object for tailwindcss means it will use default options, which is fine for most cases.

Depending on your project requirements, you might want to consider adding other PostCSS plugins. Some common ones include:

  • autoprefixer for adding vendor prefixes automatically
  • postcss-preset-env for using future CSS features
  • cssnano for minifying CSS in production

If you decide to add more plugins, you can do so like this:

const config = {
  plugins: {
    'postcss-preset-env': {},
    tailwindcss: {},
    autoprefixer: {},
    ...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {})
  },
};

This is just a suggestion, and the current configuration is perfectly valid as is.

examples/example-vite-kitchen-sink/src/dojo.config.ts (2)

5-7: LGTM: Configuration is correctly set up.

The dojoConfig is properly created and exported using the createDojoConfig function with the imported manifest.

Consider adding a brief comment at the top of the file to explain its purpose, for example:

// Configuration file for the Dojo engine in the kitchen sink example

This would improve the file's self-documentation and make it easier for other developers to understand its role in the project.


1-7: Consider enhancing the kitchen sink example.

While the current configuration is correct and functional, consider the following suggestions to make this kitchen sink example more comprehensive and educational:

  1. Add comments explaining the purpose of each part of the configuration and how it can be customized.
  2. Include examples of additional configuration options that might be useful in different scenarios.
  3. Consider adding error handling or validation for the manifest import.
  4. As mentioned in the PR objectives, ensure that appropriate documentation and tests are added for this example.

These enhancements would make the example more valuable for developers learning to use the Dojo engine in various scenarios.

examples/example-vite-kitchen-sink/.env.dist (3)

1-1: LGTM! Consider HTTPS for production.

The VITE_RPC_URL is correctly set for local development.

For production environments, consider using HTTPS instead of HTTP to ensure secure communication.


5-5: LGTM! Consider HTTPS for production.

The VITE_TORII_URL is correctly set for local development.

For production environments, consider using HTTPS instead of HTTP to ensure secure communication.


1-5: Overall suggestions for environment configuration

Thank you for adding this configuration file. Here are some overall suggestions to improve it:

  1. Consistency: Ensure all URLs are appropriate for the intended environment (development, staging, or production).
  2. Security:
    • Implement proper API key management.
    • Use HTTPS for all non-localhost URLs in production.
  3. Clarity: Clarify the distinction between VITE_CONTROLLER_URL and VITE_CONTROLLER_RPC if they serve different purposes.
  4. Best Practices:
    • Consider using environment-specific .env files (e.g., .env.development, .env.production).
    • Implement a secret management system for handling sensitive data.
    • Ensure that .env files containing real keys or sensitive data are added to .gitignore.

These changes will enhance the security, clarity, and maintainability of your configuration.

examples/example-vite-kitchen-sink/src/main.tsx (1)

9-15: LGTM with a suggestion: Consider safer root element selection.

The application rendering is correctly implemented using React 18's createRoot. The structure with RootLayout wrapping Home is good for separation of concerns.

However, the use of the non-null assertion operator (!) on getElementById("root") assumes the element always exists, which could lead to runtime errors if the element is missing.

Consider using a safer approach to handle potential missing root element:

const rootElement = document.getElementById("root");
if (rootElement) {
  createRoot(rootElement).render(
    <StrictMode>
      <RootLayout>
        <Home />
      </RootLayout>
    </StrictMode>
  );
} else {
  console.error("Root element not found");
}

This approach will prevent the application from crashing if the root element is missing and provide a helpful error message.

examples/example-vite-kitchen-sink/src/lib/utils.ts (1)

1-16: Add comments and documentation to improve code clarity.

While the code is well-structured, it lacks comments and documentation. To improve maintainability and ease of use for other developers, consider adding:

  1. A file-level comment explaining the purpose of this utility file.
  2. JSDoc comments for each function, describing their purpose, parameters, and return values.
  3. Inline comments for any complex logic, especially in the ensureStarkFelt function.

Here's an example of how you might add documentation:

/**
 * Utility functions for the kitchen sink example.
 */

import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

/**
 * Combines multiple class values into a single string and merges Tailwind classes.
 * @param inputs - Any number of class values (strings, objects, or arrays)
 * @returns A string of merged class names
 */
export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

/**
 * Ensures a string is in the correct format for a Stark felt.
 * @param value - The input string to process
 * @returns A string in the correct Stark felt format
 * @throws {Error} If the input is not a valid hexadecimal string or exceeds the maximum length
 */
export function ensureStarkFelt(value: string): string {
  // Implementation...
}

Adding such documentation will greatly improve the readability and usability of this utility file.

examples/example-vite-kitchen-sink/index.html (2)

3-8: Consider enhancing the head section for better SEO and specificity.

While the current head section is functional, consider the following improvements:

  1. Add a meta description tag for better SEO.
  2. Update the title to be more specific to the kitchen sink example.
  3. Verify the favicon path ("/vite.svg") is correct for your project structure.

Here's a suggested improvement:

 <head>
     <meta charset="UTF-8" />
     <link rel="icon" type="image/svg+xml" href="/vite.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Vite + React + TS</title>
+    <title>Kitchen Sink Example - Vite + React + TS</title>
+    <meta name="description" content="A comprehensive kitchen sink example showcasing Vite, React, and TypeScript capabilities." />
 </head>

9-12: LGTM: Proper body structure for React application.

The body section is correctly structured for a React application. The empty div with id="root" serves as the mounting point, and the script tag is properly set up to load the main TypeScript file as a module.

Consider adding a noscript tag to provide a message for users with JavaScript disabled:

 <body>
     <div id="root"></div>
+    <noscript>You need to enable JavaScript to run this app.</noscript>
     <script type="module" src="/src/main.tsx"></script>
 </body>
examples/example-vite-kitchen-sink/components.json (2)

1-5: LGTM! Consider updating documentation.

The schema and general settings look good. The use of a schema, the "new-york" style, and enabling RSC and TypeScript are all appropriate choices for a modern React project using Shadcn UI.

As this is a new example, consider updating the project documentation to mention the use of React Server Components and TypeScript in this kitchen sink example.


1-20: Overall review: Good start, but more work needed.

This configuration file is a good start for the kitchen sink example using Shadcn UI. However, there are a few points to address:

  1. Verify the CSS file path and Vite compatibility for aliases as mentioned in previous comments.
  2. Consider adding a prefix to Tailwind classes to avoid potential conflicts.
  3. Update project documentation to reflect the use of this new example.

Additionally, to complete the kitchen sink example:

  1. Implement the actual components and pages that demonstrate various Shadcn UI features.
  2. Add necessary Vite configuration files.
  3. Create a README.md file for this example, explaining its purpose and how to run it.
  4. Add tests for the example components.
  5. Set up a CI job for this example, as mentioned in the PR checklist.

Once these steps are completed, please update the PR description and mark the relevant checklist items as done.

examples/example-vite-kitchen-sink/src/env.ts (1)

4-14: Environment setup looks good, consider adding error handling.

The environment setup using createEnv is well-structured and follows best practices for Vite applications. The use of zod for validation adds type safety, which is excellent.

Consider adding error handling or default values for missing environment variables. This can help prevent runtime errors and improve the robustness of the application. For example:

VITE_RPC_URL: z.string().default("http://localhost:8545"),
VITE_RPC_API_KEY: z.string().optional(),
// ... (apply similar changes to other variables as needed)

This way, if an environment variable is missing, it will use the default value instead of throwing an error.

examples/example-vite-kitchen-sink/vite.config.ts (1)

1-6: LGTM! Consider grouping imports.

The imports look good and cover the necessary functionality for a Vite project with React, WebAssembly, and top-level await support.

Consider grouping the imports for better readability:

import { defineConfig } from "vite";
import { fileURLToPath } from "node:url";

import react from "vite-preset-react";
import topLevelAwait from "vite-plugin-top-level-await";
import wasm from "vite-plugin-wasm";
examples/example-vite-kitchen-sink/src/components/wallet-account.tsx (3)

4-6: Consider handling edge cases in shortAddress function.

The shortAddress function effectively formats typical Ethereum addresses. However, it may not handle edge cases gracefully, such as addresses shorter than 10 characters.

Consider adding a check for the address length:

 function shortAddress(address: string): string {
+  if (address.length < 10) {
+    return address; // Return the original address if it's too short
+  }
   return `${address.slice(0, 6)}...${address.slice(-4)}`;
 }

11-13: Explicitly return null for undefined address.

When the address is undefined, it's better to explicitly return null rather than implicitly returning undefined. This makes the intention clearer and adheres to React's expectations for component return values.

Consider modifying the early return:

 if (undefined === address) {
-  return
+  return null;
 }

14-16: Add type="button" to the Button component.

When using button elements, it's a good practice to explicitly set the type attribute. This prevents unintended form submissions if the button is used within a form context.

Add the type prop to the Button component:

- return <Button onClick={() => disconnect()} variant="outline" className="rounded-lg">
+ return <Button type="button" onClick={() => disconnect()} variant="outline" className="rounded-lg">
    {shortAddress(address ?? "0x")}
  </Button>
examples/example-vite-kitchen-sink/tsconfig.json (2)

2-24: Consider adding 'target' and 'baseUrl' compiler options

The compiler options look good overall and are appropriate for a modern web application using TypeScript with a bundler like Vite. However, consider adding the following options for completeness:

  1. Add a "target" option to specify the ECMAScript target version (e.g., "es2020" or "esnext").
  2. Add a "baseUrl" option, which is typically needed for the "paths" option to work correctly.

Here's a suggested addition to the compiler options:

  "compilerOptions": {
+   "target": "es2020",
+   "baseUrl": ".",
    // ... existing options ...
  }

Adjust the "target" value as needed based on your browser support requirements.


29-31: Consider expanding the 'exclude' section

The current 'exclude' section correctly ignores the 'node_modules' directory, which is a good practice.

Consider expanding the 'exclude' section to ignore other non-source directories that don't need type checking. This can further improve compilation speed. Here's a suggested expansion:

  "exclude": [
-   "node_modules"
+   "node_modules",
+   "dist",
+   "build",
+   "coverage"
  ]

Adjust the directories based on your project structure and build output locations.

examples/example-vite-kitchen-sink/src/app/layout.tsx (3)

1-6: LGTM! Consider grouping imports for better organization.

The imports look good and use absolute paths consistently. To improve readability, consider grouping imports by their origin:

  1. External libraries (e.g., React if needed)
  2. UI components
  3. Custom components
  4. Providers

Here's a suggested regrouping:

import React from 'react'; // If needed, depending on your React version

import { TooltipProvider } from "@/components/ui/tooltip";

import Sidebar from "@/components/sidebar";
import Header from "@/components/header";

import StarknetProvider from "@/components/starknet-provider";
import DojoProvider from "@/dojo/provider";

9-25: Great use of providers! Consider adding TypeScript types.

The component structure is well-organized, wrapping the application with necessary providers. This ensures that required context is available throughout the app, which is a good practice.

To improve type safety, consider adding TypeScript types to the component:

import { ReactNode } from 'react';

interface RootLayoutProps {
  children: ReactNode;
}

export default function RootLayout({ children }: RootLayoutProps) {
  // ... rest of the component
}

This change will provide better type checking and improve the overall robustness of the code.


14-20: Solid layout structure. Consider responsive design.

The layout implementation provides a good foundation for a typical application structure with a sidebar and header. The use of a grid layout is appropriate for this purpose.

Consider the following suggestions to enhance the layout:

  1. Responsive Design: The current layout doesn't show explicit handling of different screen sizes. Consider adding responsive classes to ensure the layout adapts well to various devices.

  2. Sidebar Width: The fixed left padding (pl-[53px]) suggests a fixed sidebar width. Consider making this responsive or using CSS variables for better maintainability.

  3. Accessibility: Ensure that the layout structure is accessible. Consider adding appropriate ARIA roles to the main sections (e.g., role="navigation" for the sidebar).

Example of responsive adjustments:

<div className="grid h-screen w-full pl-[53px] md:pl-[200px] lg:pl-[250px]">
  <Sidebar className="fixed left-0 top-0 h-full w-[53px] md:w-[200px] lg:w-[250px]" />
  <div className="flex flex-col w-full">
    <Header className="w-full" />
    <main className="flex-grow overflow-auto">
      {children}
    </main>
  </div>
</div>

This example assumes the use of Tailwind CSS and provides a responsive sidebar width. Adjust the specific values according to your design requirements.

examples/example-vite-kitchen-sink/src/components/ui/label.tsx (2)

7-9: LGTM: Well-defined styling with cva. Consider adding documentation.

The labelVariants function uses cva effectively to define styles for the label, including handling the disabled state. This approach promotes consistency and reusability.

Consider adding a brief comment explaining the purpose of these styles and how they interact with peer elements, especially for the peer-disabled classes. This would enhance maintainability for future developers.


11-22: LGTM: Well-structured component with proper typing. Consider adding prop documentation.

The Label component is well-defined using React.forwardRef, correctly wrapping the Radix UI component and combining styles. The TypeScript typing is appropriate, and setting the display name is good for debugging.

Consider adding JSDoc comments to document the component's props, especially any custom props added beyond the Radix UI component's props. This would improve the developer experience when using this component.

examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx (3)

1-3: LGTM! Consider using named import for React.

The imports look good. However, for better tree-shaking, consider using named imports from React instead of the namespace import.

You can update the import like this:

-import * as React from "react"
+import { forwardRef } from "react"

This change allows for more efficient bundling by only importing the specific functions you need.


7-21: LGTM! Well-structured component with a minor suggestion.

The Textarea component is well-implemented:

  • Proper use of forwardRef for ref forwarding.
  • Good practice of merging classNames.
  • Comprehensive default styles covering various states and accessibility.
  • Correct prop spreading for flexibility.
  • Setting of displayName for debugging.

Consider destructuring forwardRef in the import to align with the suggestion for the React import:

-const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
+const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(

This change would make the code more consistent if you update the import as suggested earlier.


1-23: Great implementation, but don't forget about tests and documentation!

The Textarea component is well-implemented, following React best practices and providing a flexible, styled textarea input. However, as per the PR objectives, there are a few items that still need to be addressed:

  1. Tests: Add unit tests for this component to ensure its functionality.
  2. Documentation: Update or create documentation explaining how to use this component.
  3. CI Job: Create a dedicated CI job for the new examples, including this component.

Consider creating a README.md file in the example-vite-kitchen-sink directory to provide an overview of the example and how to use its components. This would help fulfill the documentation requirement mentioned in the PR objectives.

examples/example-vite-kitchen-sink/src/dojo/models.ts (2)

21-34: LGTM with a suggestion: Consider the implications of the hardcoded global_counter_key.

The schema constant correctly implements the OnchainDashSchemaType interface and provides appropriate default values for all fields. However, there's a potential concern:

  • The global_counter_key is hardcoded to 9999999. Consider if this value should be more dynamic or configurable, as it might limit the flexibility of the system.

Consider replacing the hardcoded value with a more flexible approach:

export const DEFAULT_GLOBAL_COUNTER_KEY = 9999999;

export const schema: OnchainDashSchemaType = {
  onchain_dash: {
    GlobalCounter: {
      fieldOrder: ["counter", "global_counter_key"],
      counter: 0,
      global_counter_key: DEFAULT_GLOBAL_COUNTER_KEY,
    },
    // ... rest of the schema
  },
};

This change would make it easier to modify the default value in the future and potentially allow for runtime configuration.


1-35: Overall, the file structure and implementation are well-designed.

This new TypeScript file introduces a robust foundation for managing counters in an on-chain dashboard context. The interfaces are clearly defined, and the schema provides a structured way to initialize and manage the counters. The code is well-organized and follows TypeScript best practices.

A minor suggestion has been made regarding the hardcoded global_counter_key value, which could be made more flexible for future adaptability.

As this file seems to be part of a larger "kitchen sink" example, ensure that:

  1. The purpose and usage of these counters are well-documented in the broader context of the example.
  2. Any components or services that interact with this schema are consistent with the defined structure.
  3. Consider adding comments to explain the significance of the global_counter_key and its default value, especially if it has specific implications in the Dojo Engine context.
examples/example-vite-kitchen-sink/src/components/ui/input.tsx (1)

7-21: LGTM: Well-structured component with room for minor improvement.

The Input component is well-implemented using forwardRef, correctly handles props, and uses the cn utility for class composition. The comprehensive set of CSS classes provides good styling coverage.

Consider extracting the long className string into a separate constant for improved readability:

const inputClasses = "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50";

// Then in the component:
className={cn(inputClasses, className)}

This change would make the component more maintainable and easier to read.

examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (1)

22-32: LGTM: Render method is well-implemented. Consider adding accessibility improvements.

The render method correctly implements the theme switch UI with appropriate icons and a controlled Switch component. The use of Tailwind CSS classes for styling is consistent with modern React practices.

To improve accessibility, consider adding an aria-label to the Switch component:

 <Switch
   checked={theme === 'dark'}
   onCheckedChange={toggleTheme}
   className="data-[state=checked]:bg-slate-800"
+  aria-label="Toggle dark mode"
 />

This change will provide better context for screen reader users, enhancing the overall accessibility of the component.

examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (3)

1-12: LGTM! Consider grouping imports for better readability.

The imports are appropriate for the component's functionality. Good use of named imports for better tree-shaking.

Consider grouping the imports for better readability:

import type { PropsWithChildren } from "react";
import { Chain, mainnet } from "@starknet-react/chains";
import {
  argent,
  braavos,
  jsonRpcProvider,
  StarknetConfig,
  useInjectedConnectors,
  voyager,
} from "@starknet-react/core";
import CartridgeConnector from "@cartridge/connector";
import { env, getRpcUrl } from "@/env";

14-44: Good component structure. Consider performance optimization.

The component structure follows React best practices and correctly uses PropsWithChildren for a wrapper component.

Consider moving the setup of the provider and connectors outside the component to prevent unnecessary re-renders:

const provider = jsonRpcProvider({
  rpc: (chain: Chain) => ({ nodeUrl: getRpcUrl() })
});

const { connectors: injectedConnectors } = useInjectedConnectors({
  recommended: [argent(), braavos()],
  includeRecommended: "onlyIfNoConnectors",
  order: "alphabetical",
});

const cartridgeConnector = new CartridgeConnector({
  url: env.VITE_CONTROLLER_URL,
  rpc: env.VITE_CONTROLLER_RPC,
});

export default function StarknetProvider({ children }: PropsWithChildren) {
  return (
    <StarknetConfig
      chains={[mainnet]}
      provider={provider}
      connectors={[cartridgeConnector, ...injectedConnectors]}
      explorer={voyager}
      autoConnect
    >
      {children}
    </StarknetConfig>
  );
}

This change will ensure that these objects are not recreated on every render.


27-42: Configuration looks good. Consider making autoConnect configurable.

The StarknetConfig setup is appropriate for a mainnet configuration, and the use of environment variables for the CartridgeConnector provides good flexibility.

Consider making the autoConnect prop configurable:

interface StarknetProviderProps extends PropsWithChildren {
  autoConnect?: boolean;
}

export default function StarknetProvider({ children, autoConnect = true }: StarknetProviderProps) {
  // ... existing code ...

  return (
    <StarknetConfig
      // ... other props ...
      autoConnect={autoConnect}
    >
      {children}
    </StarknetConfig>
  );
}

This change allows users of the StarknetProvider to decide whether they want auto-connection behavior, improving the component's flexibility.

examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx (3)

6-10: LGTM: Component definitions are correct. Consider adding type annotations for consistency.

The TooltipProvider, Tooltip, and TooltipTrigger components are correctly defined and re-exported. This pattern allows for easier customization and consistent usage across the application.

For consistency and improved type safety, consider adding explicit type annotations:

-const TooltipProvider = TooltipPrimitive.Provider
-const Tooltip = TooltipPrimitive.Root
-const TooltipTrigger = TooltipPrimitive.Trigger
+const TooltipProvider: React.FC<TooltipPrimitive.TooltipProviderProps> = TooltipPrimitive.Provider
+const Tooltip: React.FC<TooltipPrimitive.TooltipProps> = TooltipPrimitive.Root
+const TooltipTrigger: React.FC<TooltipPrimitive.TooltipTriggerProps> = TooltipPrimitive.Trigger

12-26: LGTM: TooltipContent component is well-implemented. Consider extracting prop types for better maintainability.

The TooltipContent component is correctly implemented using React.forwardRef, extending the Radix UI TooltipContent with additional styling and animation classes. The use of the cn utility function for class name management is a good practice.

For improved maintainability and reusability, consider extracting the prop types into a separate interface:

interface TooltipContentProps extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> {
  sideOffset?: number;
}

const TooltipContent = React.forwardRef<
  React.ElementRef<typeof TooltipPrimitive.Content>,
  TooltipContentProps
>(({ className, sideOffset = 4, ...props }, ref) => (
  // ... rest of the implementation
))

This change would make it easier to understand and potentially extend the component's props in the future.


1-28: Overall, excellent implementation. Consider adding tests and documentation.

The tooltip component is well-implemented using Radix UI primitives and follows React best practices. It provides a solid foundation for the kitchen sink example mentioned in the PR objectives.

To further improve the component:

  1. Add unit tests to ensure the component behaves correctly under different scenarios.
  2. Include inline documentation or JSDoc comments to explain the purpose and usage of each exported component.
  3. Consider creating a README.md file in the components/ui directory to provide an overview of the available UI components and their usage.

These additions would enhance the maintainability and usability of the component library.

examples/example-vite-kitchen-sink/src/components/ui/switch.tsx (2)

6-9: LGTM: Component definition is well-structured and type-safe.

The use of React.forwardRef and TypeScript types is excellent, ensuring type safety and allowing proper ref forwarding. The component accepts all props from the Radix UI Switch Root, which provides flexibility.

Consider adding a custom props interface if you need to extend the component with additional props in the future. For example:

interface SwitchProps extends React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> {
  // Add any custom props here
}

const Switch = React.forwardRef<
  React.ElementRef<typeof SwitchPrimitives.Root>,
  SwitchProps
>(({ className, ...props }, ref) => (
  // ... rest of the component
))

This approach would make it easier to add custom props while maintaining type safety.


10-23: LGTM: Component implementation is robust and follows best practices.

The Switch component is well-implemented, utilizing Radix UI primitives and Tailwind CSS for styling. The use of data attributes for state-based styling and the handling of various component states (checked, unchecked, disabled, focus) is commendable.

Consider enhancing accessibility by adding an aria-label or aria-labelledby prop. This would allow users to provide descriptive labels for screen readers. You could implement this as follows:

interface SwitchProps extends React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> {
  ariaLabel?: string;
}

const Switch = React.forwardRef<
  React.ElementRef<typeof SwitchPrimitives.Root>,
  SwitchProps
>(({ className, ariaLabel, ...props }, ref) => (
  <SwitchPrimitives.Root
    className={cn(
      // ... existing classes
    )}
    aria-label={ariaLabel}
    {...props}
    ref={ref}
  >
    {/* ... rest of the component */}
  </SwitchPrimitives.Root>
))

This change would allow users of the component to provide accessible labels when necessary.

examples/example-vite-kitchen-sink/src/dojo/provider.tsx (2)

10-10: LGTM: Context creation with proper typing.

The DojoContext is well-defined with the correct type SDK<OnchainDashSchemaType>. This ensures type safety when using the context throughout the application.

Consider using a more descriptive initial state instead of null. For example:

export const DojoContext = createContext<SDK<OnchainDashSchemaType> | { status: 'initializing' }>({ status: 'initializing' });

This approach provides more information about the context's state before initialization.


15-45: LGTM: Well-structured DojoProvider component with some suggestions for improvement.

The DojoProvider component is well-implemented, using useEffect for async initialization and properly providing the context to its children. However, there are a few points to consider:

  1. The world address is hardcoded. Consider moving this to an environment variable for better flexibility across different environments.

  2. Error handling could be improved. Currently, errors are only logged to the console.

  3. Move the world address to an environment variable:

-worldAddress: "0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12",
+worldAddress: env.VITE_WORLD_ADDRESS,
  1. Improve error handling:
-}).then(setDb).catch(console.error);
+}).then(setDb).catch((error) => {
+  console.error("Failed to initialize Dojo SDK:", error);
+  // Consider setting an error state here and displaying it to the user
+});

These changes will make the component more flexible and robust.

examples/example-vite-kitchen-sink/package.json (5)

1-4: LGTM with a minor suggestion for the project name.

The basic project information is set up correctly. The version follows semantic versioning, and marking the project as private is appropriate for an example.

Consider renaming the project to "kitchen-sink-example" or similar to make it more descriptive and align with the PR title.


5-10: LGTM with a suggestion for an additional script.

The scripts section includes essential commands for development, building, linting, and previewing the application. The build script correctly includes TypeScript compilation before the Vite build.

Consider adding a separate type-check script to run TypeScript type checking without compilation:

 "scripts": {
   "dev": "vite",
   "build": "tsc -b && vite build",
   "lint": "eslint .",
-  "preview": "vite preview"
+  "preview": "vite preview",
+  "type-check": "tsc --noEmit"
 },

This allows developers to quickly check for type errors without running a full build.


11-39: LGTM with suggestions for dependency optimization.

The dependencies section includes appropriate libraries for a React project with StarkNet integration. The use of workspace references for some packages suggests a monorepo structure, which is fine.

Consider the following optimizations:

  1. Evaluate the necessity of all dependencies for a kitchen sink example. Some libraries like @t3-oss/env-nextjs might not be needed if you're not using Next.js.

  2. Consider using more specific versions for dependencies instead of ^ to ensure consistent builds. For example:

-    "react": "^18",
+    "react": "18.2.0",
  1. Ensure that all workspace dependencies are actually needed in this example:
     "@dojoengine/core": "workspace:*",
     "@dojoengine/sdk": "workspace:*",
  1. Review if all Radix UI components are necessary for the kitchen sink example. Remove any that are not actively used.

40-54: LGTM with suggestions for devDependencies optimization.

The devDependencies section includes appropriate tools for a modern React project using Vite and TypeScript.

Consider the following optimizations:

  1. Remove eslint-config-next if you're not using Next.js in this example:
-    "eslint-config-next": "14.2.12",
  1. Ensure that the TypeScript version matches the one used in the main project:
-    "typescript": "^5",
+    "typescript": "5.4.2", // Replace with the exact version used in the main project
  1. Consider adding @typescript-eslint/eslint-plugin and @typescript-eslint/parser for better TypeScript linting support.

  2. Review if all Vite plugins are necessary for this example. Remove any that are not actively used.

  3. Add autoprefixer as it's typically used alongside Tailwind CSS:

+    "autoprefixer": "^10.4.18",

1-55: Overall, the package.json file is well-structured but needs some refinements.

The file provides a good starting point for a kitchen sink example in the dojo.js project. However, there are several areas where it can be improved to better align with the PR objectives:

  1. The project name could be more descriptive.
  2. Some dependencies and devDependencies may not be necessary for this example.
  3. Version specifications could be more precise to ensure consistent builds.

To address the PR objectives:

  • Update the documentation to explain the purpose and contents of this kitchen sink example.
  • Ensure that all necessary dependencies for the example are included and remove any unused ones.
  • Add tests specific to this example if needed.
  • Create a dedicated CI job for this new example.
  • Perform a self-review of the code, addressing the suggestions made in this review.

Consider creating a README.md file in the examples/example-vite-kitchen-sink/ directory to explain the purpose of this example, its features, and how to run it. This will help users understand the context and usage of this kitchen sink example within the dojo.js project.

examples/example-vite-kitchen-sink/src/components/ui/button.tsx (4)

7-34: LGTM: Well-structured button variants with a suggestion for improvement.

The buttonVariants constant effectively uses cva to define a comprehensive set of styles for different button types and sizes. This approach promotes consistency and maintainability in the UI.

Consider adding an aria-disabled attribute when the button is disabled for better accessibility. You can modify the base class string as follows:

-  "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
+  "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:cursor-not-allowed",

This addition will improve the accessibility of the button component when it's in a disabled state.


36-40: LGTM: Well-defined ButtonProps interface with a suggestion for improvement.

The ButtonProps interface correctly extends both React's button HTML attributes and the VariantProps from class-variance-authority. The inclusion of the asChild prop supports the component's polymorphic capabilities.

Consider adding JSDoc comments to explain the purpose of the asChild prop:

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  /**
   * When true, the button will be treated as an child element.
   * Useful for creating composite components with the button's functionality.
   */
  asChild?: boolean
}

This addition will improve the self-documentation of the component and assist other developers in understanding its usage.


42-54: LGTM: Well-implemented Button component with a suggestion for improvement.

The Button component is correctly implemented using React.forwardRef, which allows it to be used in more complex component structures. The use of the Slot component for polymorphic behavior when asChild is true is a good practice. The component also correctly applies the variant styles using the cn utility function.

Consider adding a type assertion to improve type safety when spreading props:

- <Comp
-   className={cn(buttonVariants({ variant, size, className }))}
-   ref={ref}
-   {...props}
- />
+ <Comp
+   className={cn(buttonVariants({ variant, size, className }))}
+   ref={ref}
+   {...(props as React.ButtonHTMLAttributes<HTMLButtonElement>)}
+ />

This change ensures that only valid button props are spread onto the component, which can help catch potential type errors earlier in development.


1-56: Overall: Excellent implementation of a flexible Button component.

This Button component is well-implemented, utilizing modern React patterns, Radix UI for polymorphic behavior, and class-variance-authority for flexible styling. The code is clean, maintainable, and follows best practices for React component development.

Regarding the PR objectives:

  1. The component adds a comprehensive "kitchen sink" example for buttons, which aligns with the PR's main goal.
  2. The implementation includes various button variants and sizes, providing a good showcase of possibilities.

However, to fully meet the PR objectives:

  1. Ensure that documentation is updated to include usage examples of this new Button component.
  2. Add unit tests to verify the component's behavior under different prop combinations.
  3. Consider creating a dedicated CI job for this new example, as mentioned in the PR checklist.
  4. Complete a self-review of the code, addressing any potential issues not caught in this review.

As this component is part of a larger UI system, consider the following:

  1. Ensure consistency with other UI components in terms of styling approach and prop patterns.
  2. If not already done, consider creating a storybook or similar documentation tool to showcase the various button states and variants.
  3. Think about how this component will integrate with form libraries or other common use cases in your application.
examples/example-vite-kitchen-sink/tailwind.config.ts (2)

10-53: LGTM: Comprehensive color scheme with room for improvement.

The color scheme is well-structured and uses HSL values, which is great for flexibility. The chart colors are consistently numbered.

Consider extracting the color definitions into a separate file for better maintainability, especially if these colors are used across multiple configurations or components. This could look like:

// colors.ts
export const colors = {
  background: 'hsl(var(--background))',
  foreground: 'hsl(var(--foreground))',
  // ... other color definitions
};

// tailwind.config.ts
import { colors } from './colors';

const config: Config = {
  // ...
  theme: {
    extend: {
      colors,
      // ...
    }
  }
  // ...
};

61-63: LGTM: Plugin inclusion and export.

The "tailwindcss-animate" plugin is correctly included, and the configuration is properly exported.

Consider adding a comment explaining the purpose and benefits of the "tailwindcss-animate" plugin for better documentation. For example:

// Add the tailwindcss-animate plugin for easy-to-use animations
plugins: [require("tailwindcss-animate")],
examples/example-vite-kitchen-sink/src/app/globals.css (3)

16-45: Comprehensive set of theme variables for light mode.

The light mode theme variables are well-defined and cover a wide range of UI elements and states. The use of HSL color values is a good choice for easy color manipulation.

Consider grouping related variables (e.g., all background colors, all foreground colors) for improved readability. For example:

:root {
  /* Backgrounds */
  --background: 0 0% 100%;
  --card: 0 0% 100%;
  --popover: 0 0% 100%;
  
  /* Foregrounds */
  --foreground: 240 10% 3.9%;
  --card-foreground: 240 10% 3.9%;
  --popover-foreground: 240 10% 3.9%;
  
  /* ... other groups ... */
}

46-71: Well-structured dark mode theme variables.

The dark mode theme variables are appropriately defined and provide a good contrast to the light mode. The different chart colors for dark mode are a nice touch for improved visibility.

To improve maintainability, consider using CSS custom property fallbacks to only override the colors that change in dark mode. For example:

.dark {
  --background: 240 10% 3.9%;
  --foreground: 0 0% 98%;
  /* Only override other colors that actually change */
}

This approach would reduce duplication and make it easier to manage theme changes in the future.


74-85: Base layer styles provide a solid foundation.

The base layer styles are well-structured and provide a good foundation for the application. The use of @apply for Tailwind classes and CSS variables for font families is appropriate.

Consider adding a line height to the body and headings for improved readability. For example:

body {
  @apply bg-background text-foreground;
  font-family: var(--font-geist-sans);
  line-height: 1.5;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-geist-sans);
  line-height: 1.2;
}

Also, note that h7 is not a valid HTML heading element. You can remove it from the selector list.

examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (3)

17-21: Consider adding displayName to aliased components.

The DrawerTrigger, DrawerPortal, and DrawerClose components are cleanly aliased from the DrawerPrimitive components. However, for consistency with other components in this file and to improve debugging experience, consider adding displayName properties to these components.

You can add the displayName properties like this:

DrawerTrigger.displayName = "DrawerTrigger"
DrawerPortal.displayName = "DrawerPortal"
DrawerClose.displayName = "DrawerClose"

35-54: LGTM: DrawerContent component is well-implemented. Consider accessibility improvement.

The DrawerContent component is well-structured, using forwardRef and providing a comprehensive wrapper for the drawer content. The inclusion of DrawerPortal and DrawerOverlay enhances the component's functionality.

For improved accessibility, consider adding an aria-label to the loading indicator div:

- <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
+ <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" aria-label="Loading indicator" />

1-116: Overall, excellent implementation of the Drawer component.

This file introduces a well-structured and comprehensive Drawer component, effectively utilizing the 'vaul' library. The implementation follows React best practices, including the use of forwardRef, proper prop handling, and consistent styling approaches.

Regarding the PR objectives:

  1. The kitchen sink example has been successfully added with this Drawer component.
  2. The code demonstrates good quality and follows best practices.

However, to fully meet the PR objectives:

  1. Ensure that documentation is updated to include usage examples of this new Drawer component.
  2. Add unit tests for the Drawer component and its subcomponents.
  3. Create a dedicated CI job for this new example, if not already done.
  4. Complete a self-review of the code, addressing any remaining TODOs or FIXMEs.

Consider creating a separate file for commonly used utility functions like 'cn' if it's used across multiple components. This can improve maintainability and reduce duplication.

examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (2)

15-28: LGTM: DialogOverlay component is well-implemented with a minor suggestion.

The DialogOverlay component is correctly implemented as a forward-ref component, wrapping DialogPrimitive.Overlay. The use of the cn utility for class name management and data attributes for animations is a good practice.

Consider breaking the long className string into multiple lines for improved readability:

 className={cn(
-  "fixed inset-0 z-50 bg-black/80  data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
+  "fixed inset-0 z-50 bg-black/80",
+  "data-[state=open]:animate-in data-[state=closed]:animate-out",
+  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
   className
 )}

30-52: LGTM: DialogContent component is well-implemented with suggestions for improvement.

The DialogContent component is correctly implemented as a forward-ref component, wrapping DialogPrimitive.Content. The use of DialogPortal and DialogOverlay is appropriate, and the close button is well-implemented with accessibility considerations.

Consider the following improvements for better readability and maintainability:

  1. Break down the long className string into multiple lines or consider extracting it into a separate constant:
const dialogContentClasses = cn(
  "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]",
  "gap-4 border bg-background p-6 shadow-lg duration-200",
  "data-[state=open]:animate-in data-[state=closed]:animate-out",
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
  "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
  "data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%]",
  "data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
  "sm:rounded-lg",
  className
)
  1. Extract the close button into a separate component for better modularity:
const DialogCloseButton = () => (
  <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
    <Cross2Icon className="h-4 w-4" />
    <span className="sr-only">Close</span>
  </DialogPrimitive.Close>
)

These changes will improve the overall readability and maintainability of the component.

examples/example-vite-kitchen-sink/src/components/global-counter.tsx (3)

85-85: Remove unnecessary space before the colon

There is an extra space before the colon in Count : {count}. For consistency and proper formatting, it should be Count: {count}.

Apply this diff:

-          Count : {count}
+          Count: {count}

88-88: Remove space before the exclamation mark

There is an unnecessary space before the exclamation mark in the button text Click me !. It should be Click me! for proper punctuation.

Apply this diff:

-          <Button variant="outline" className="rounded-lg" onClick={handleGlobalClick}>Click me !</Button>
+          <Button variant="outline" className="rounded-lg" onClick={handleGlobalClick}>Click me!</Button>

31-31: Omit unnecessary empty callback function

The db.getEntities method is being called with an empty callback function. If the callback is not needed, you can omit it to simplify the code.

Apply this diff:

         });
-      }, ({ data, error }) => { });
examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (2)

84-84: Remove extra space before colon

There is an extra space before the colon in the text. For consistency and readability, remove the space.

Apply this change:

-           Count : {count}
+           Count: {count}

87-87: Correct spacing in button text

The button text includes a space before the exclamation mark. Typically, there should be no space before punctuation marks like exclamation points.

Apply this change:

-           <Button variant="outline" className="rounded-lg" onClick={handleCallerClick}>Click me !</Button>
+           <Button variant="outline" className="rounded-lg" onClick={handleCallerClick}>Click me!</Button>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 69662d1 and f4bd1d7.

⛔ Files ignored due to path filters (4)
  • examples/example-vite-kitchen-sink/src/app/favicon.ico is excluded by !**/*.ico
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistMonoVF.woff is excluded by !**/*.woff
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistVF.woff is excluded by !**/*.woff
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (39)
  • .gitmodules (1 hunks)
  • examples/example-vite-kitchen-sink/.env.dist (1 hunks)
  • examples/example-vite-kitchen-sink/.eslintrc.json (1 hunks)
  • examples/example-vite-kitchen-sink/.gitignore (1 hunks)
  • examples/example-vite-kitchen-sink/README.md (1 hunks)
  • examples/example-vite-kitchen-sink/components.json (1 hunks)
  • examples/example-vite-kitchen-sink/index.html (1 hunks)
  • examples/example-vite-kitchen-sink/package.json (1 hunks)
  • examples/example-vite-kitchen-sink/postcss.config.mjs (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/globals.css (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/layout.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/page.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/header.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/models.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/env.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/lib/utils.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/main.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/onchain (1 hunks)
  • examples/example-vite-kitchen-sink/tailwind.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/tsconfig.json (1 hunks)
  • examples/example-vite-kitchen-sink/vite.config.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • examples/example-vite-kitchen-sink/src/onchain
🧰 Additional context used
🪛 Biome
examples/example-vite-kitchen-sink/src/dojo/provider.tsx

[error] 12-14: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

🔇 Additional comments (86)
examples/example-vite-kitchen-sink/postcss.config.mjs (3)

1-1: LGTM: Proper type annotation for PostCSS config

The type annotation is correctly using JSDoc syntax to reference the Config type from 'postcss-load-config'. This provides valuable type information for TypeScript-aware editors, enhancing developer experience and code quality.


8-8: LGTM: Proper use of ES6 module syntax

The configuration object is correctly exported using ES6 module syntax. This is the recommended approach for modern JavaScript projects and works well with build tools like Vite.


1-8: Overall assessment: Well-structured PostCSS configuration for kitchen sink example

This PostCSS configuration file is well-structured and appropriate for a kitchen sink example using Tailwind CSS. It aligns with the PR objective of adding a comprehensive example to the dojo.js project. The use of type annotations, correct configuration structure, and modern JavaScript syntax demonstrates good coding practices.

While the current configuration is sufficient, consider expanding it with additional PostCSS plugins as the project grows, to showcase more advanced CSS processing capabilities in your kitchen sink example.

examples/example-vite-kitchen-sink/src/dojo.config.ts (1)

1-3: LGTM: Imports are correctly set up.

The necessary imports for the Dojo configuration are properly included. The createDojoConfig function is imported from the core package, and the manifest is imported from a local JSON file.

examples/example-vite-kitchen-sink/.env.dist (3)

2-2: Verify the empty API key and consider secure key management.

The VITE_RPC_API_KEY is currently set to an empty string. Please clarify if this is intentional for local development or if a key needs to be added.

For improved security:

  1. Consider using environment-specific .env files (e.g., .env.development, .env.production) to manage different configurations.
  2. Implement a secret management system for handling sensitive data like API keys.
  3. Ensure that .env files containing real keys are added to .gitignore to prevent accidental commits.

3-3: Verify use of production URL for local development.

The VITE_CONTROLLER_URL is set to a production URL ("https://x.cartridge.gg/mainnet").

Please confirm if using a production URL is intended for local development. If not, consider:

  1. Using environment-specific URLs (e.g., local, staging, production).
  2. Implementing environment-specific .env files to manage different configurations.
  3. Using a local or staging URL for development to prevent accidental interactions with the production environment.

4-4: Clarify the distinction between VITE_CONTROLLER_URL and VITE_CONTROLLER_RPC.

The VITE_CONTROLLER_RPC is set to the same value as VITE_CONTROLLER_URL.

Please clarify:

  1. Are these variables intended to have the same value?
  2. If not, what should be the correct value for VITE_CONTROLLER_RPC?
  3. If they are meant to be different, consider renaming or adding comments to clarify their distinct purposes.

Additionally, as mentioned earlier, verify if using a production URL is appropriate for local development.

.gitmodules (1)

1-3: LGTM: Existing submodule configuration is correct.

The configuration for the "dojo-starter" submodule remains unchanged and appears to be correct.

examples/example-vite-kitchen-sink/src/main.tsx (2)

1-7: LGTM: Imports are well-structured and follow best practices.

The import statements are correctly organized, importing necessary React components, local components, and global styles. The use of StrictMode is a good practice for development.


1-15: Address PR objectives and checklist items.

While this file sets up a basic React application, it doesn't fully address the objectives of a comprehensive "kitchen sink" example. Consider the following points:

  1. Expand this example to showcase more features of dojo.js, making it a true "kitchen sink" demonstration.

  2. Update the documentation to explain the purpose and features of this kitchen sink example.

  3. Add tests for the components and functionality demonstrated in this example.

  4. Create a dedicated CI job for this new example, as mentioned in the PR checklist.

  5. Ensure all items in the PR checklist are addressed before considering this PR ready for review.

To help verify the completeness of the PR, you can run the following script:

This script will help identify if tests, documentation, and CI configurations have been added or updated for the kitchen sink example.

examples/example-vite-kitchen-sink/src/lib/utils.ts (1)

1-6: LGTM: Imports and cn function look good.

The import statements and the cn function are well-implemented. The function effectively combines clsx for class name concatenation and twMerge for Tailwind class merging, which is a common and useful pattern in Tailwind CSS projects.

examples/example-vite-kitchen-sink/index.html (1)

1-2: LGTM: Proper HTML5 and language declaration.

The HTML5 doctype and language declaration are correctly implemented, following best practices for web accessibility and internationalization.

examples/example-vite-kitchen-sink/components.json (1)

13-19: Verify Vite compatibility for aliases.

The aliases configuration looks good and comprehensive, covering common project structure elements. This will improve import readability and maintainability.

However, ensure that these aliases are compatible with your Vite setup. The "@/" prefix is common in Next.js projects but might require additional configuration in Vite. Verify that your Vite configuration (usually in vite.config.ts) includes the necessary alias settings.

Run the following script to check for Vite configuration:

#!/bin/bash
# Description: Check for Vite configuration file and alias settings

# Test: Look for Vite configuration file
vite_config=$(fd -e ts -e js -d 1 '^vite.config')

if [ -n "$vite_config" ]; then
    echo "Vite configuration found: $vite_config"
    echo "Checking for alias configuration:"
    rg --type typescript --type javascript 'alias' "$vite_config"
else
    echo "No Vite configuration file found in the root directory."
    echo "Please ensure that aliases are properly configured for Vite."
fi
examples/example-vite-kitchen-sink/.gitignore (1)

10-10: LGTM: Testing and debugging ignore patterns

The ignore patterns for testing coverage, miscellaneous files, and debug logs are appropriate and follow best practices.

Also applies to: 19-26

examples/example-vite-kitchen-sink/src/env.ts (3)

1-2: LGTM: Imports are correct and necessary.

The imports for createEnv from "@t3-oss/env-core" and z from "zod" are appropriate for setting up environment variables with validation.


1-18: Overall, good implementation with room for minor improvements.

This new file sets up environment variables correctly for a Vite application in the dojo.js project's kitchen sink example. It uses modern practices like zod for validation, which is commendable. The suggestions for improvement include:

  1. Adding error handling or default values for environment variables.
  2. Refactoring the getRpcUrl function for better readability and security.

These changes will enhance the robustness and maintainability of the code.

As this is part of a new kitchen sink example, ensure that:

  1. The example is well-documented, explaining the purpose of each environment variable.
  2. There's a sample .env file or documentation on how to set up these environment variables for users trying out the example.
  3. The example demonstrates best practices for environment variable usage in dojo.js projects.

To ensure the completeness of the kitchen sink example, please check for the presence of a README or documentation file:

#!/bin/bash
# Check for README or documentation in the kitchen sink example directory
fd -t f "(README|documentation)\.(md|txt)" examples/example-vite-kitchen-sink

16-18: 🛠️ Refactor suggestion

Improve getRpcUrl function for better readability and security.

The getRpcUrl function correctly uses the environment variables and has the right logic for appending the API key. However, there are a few improvements we can make:

  1. Use template literals for better readability.
  2. Use URL constructor for proper URL handling and encoding.
  3. Consider using a more secure method for API key transmission (e.g., headers instead of query parameters).

Here's a suggested refactor:

export function getRpcUrl() {
  const url = new URL(env.VITE_RPC_URL);
  if (env.VITE_RPC_API_KEY) {
    url.searchParams.append('apikey', env.VITE_RPC_API_KEY);
  }
  return url.toString();
}

This version uses the URL API, which handles proper encoding of parameters and is generally more robust for URL manipulation.

To ensure this change doesn't break existing functionality, please verify all usages of getRpcUrl() in the codebase:

✅ Verification successful

Verification Complete: No Issues Found with getRpcUrl Usage.

The getRpcUrl function is used in the following locations:

  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx

All usages appear compatible with the proposed changes. The refactored getRpcUrl function should improve readability and security without affecting existing functionality.


🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for all usages of getRpcUrl() in the codebase
rg "getRpcUrl\(\)" --type typescript

Length of output: 124


Script:

#!/bin/bash
# Search for all usages of getRpcUrl() in the entire codebase
rg "getRpcUrl\(\)"

Length of output: 296

examples/example-vite-kitchen-sink/vite.config.ts (1)

10-10: LGTM! Plugins are correctly configured.

The necessary plugins (react, wasm, and topLevelAwait) are correctly included in the configuration.

examples/example-vite-kitchen-sink/src/components/wallet-account.tsx (2)

1-2: LGTM: Imports are appropriate and concise.

The imports from @starknet-react/core and the local UI component are relevant to the component's functionality.


1-17: Well-structured component aligning with PR objectives.

The WalletAccount component is a well-implemented addition to the kitchen sink example for the dojo.js project. It demonstrates the integration with Starknet's React hooks and provides a clean, focused implementation of wallet account display and disconnection functionality.

A few minor improvements have been suggested, but overall, this component contributes positively to the PR's objective of adding a comprehensive example to the project.

To ensure this component is properly integrated into the kitchen sink example, let's verify its usage:

✅ Verification successful

[/run_scripts]


WalletAccount component usage verified.

The WalletAccount component is properly imported and utilized within header.tsx. No issues found regarding its integration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for the usage of WalletAccount component in other files

# Test: Search for WalletAccount import or usage
rg --type typescript --type tsx "import.*WalletAccount|<WalletAccount" ./examples/example-vite-kitchen-sink

Length of output: 144


Script:

#!/bin/bash
# Description: Check for the usage of WalletAccount component in other files

# Test: Search for WalletAccount import or usage using correct file types
rg --type ts --type tsx "import.*WalletAccount|<WalletAccount" ./examples/example-vite-kitchen-sink

Length of output: 129


Script:

#!/bin/bash
# Description: Check for the usage of WalletAccount component in other files

# Test: Search for WalletAccount import or usage using the correct file type
rg --type typescript "import.*WalletAccount|<WalletAccount" ./examples/example-vite-kitchen-sink

Length of output: 133


Script:

#!/bin/bash
# Description: Check for the usage of WalletAccount component in other files

# Test: Search for WalletAccount import or usage using glob patterns for .ts and .tsx files
rg "import.*WalletAccount|<WalletAccount" ./examples/example-vite-kitchen-sink -g "*.ts" -g "*.tsx"

Length of output: 298

examples/example-vite-kitchen-sink/tsconfig.json (1)

1-32: Overall, good configuration with minor improvements needed

The tsconfig.json file is well-structured and appropriate for a modern TypeScript project, likely using Vite as a bundler. The configuration will enable strict type checking, modern module resolution, and other beneficial TypeScript features.

A few minor improvements have been suggested in the previous comments, including:

  1. Adding 'target' and 'baseUrl' compiler options
  2. Fixing a syntax error in the 'include' section
  3. Considering expansion of the 'exclude' section

As this is part of a new kitchen sink example for the dojo.js project, please ensure that:

  1. The example demonstrates key features of dojo.js
  2. Documentation is updated to reference this new example
  3. Any necessary tests are added
  4. A CI job is created for this example, as mentioned in the PR checklist

You can use the following script to check if documentation has been updated:

If this search doesn't yield results, consider updating the project documentation to mention this new example.

examples/example-vite-kitchen-sink/src/app/layout.tsx (1)

1-25: Overall, good implementation with room for minor enhancements.

This new RootLayout component provides a solid foundation for the kitchen sink example mentioned in the PR objectives. It effectively sets up the main application structure and wraps the content with necessary providers.

Key strengths:

  1. Proper use of providers to ensure context availability.
  2. Clear and logical layout structure.
  3. Separation of concerns with separate components for Sidebar and Header.

Suggestions for improvement:

  1. Add TypeScript types for better type safety.
  2. Enhance responsive design capabilities.
  3. Consider accessibility improvements.
  4. Organize imports for better readability.

These enhancements will further improve the code quality and maintainability of this kitchen sink example.

To ensure this component is properly integrated into the application, let's verify its usage:

This script will help us confirm that the RootLayout component is being imported and used correctly in other parts of the application.

✅ Verification successful

To proceed with verifying the usage of the RootLayout component, please run the following updated shell scripts:


To accurately verify the usage of the RootLayout component, please execute the following updated shell scripts:


Verification Successful: RootLayout is correctly integrated.

The RootLayout component is properly imported and utilized in examples/example-vite-kitchen-sink/src/main.tsx, ensuring it is correctly integrated into the application.

  • Import Statement:
    • import RootLayout from "./app/layout"; in main.tsx
  • Component Usage:
    • <RootLayout> is used within main.tsx

No issues were found with the integration of RootLayout.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of RootLayout component

# Test: Search for imports of RootLayout
echo "Searching for RootLayout imports:"
rg --type typescript --type tsx "import.*RootLayout.*from.*layout"

# Test: Search for usage of RootLayout component
echo "Searching for RootLayout usage:"
rg --type typescript --type tsx "<RootLayout"

Length of output: 336


Script:

#!/bin/bash
# Description: Verify the usage of RootLayout component

# Test: Search for imports of RootLayout
echo "Searching for RootLayout imports:"
rg --type ts --type tsx "import.*RootLayout.*from.*layout"

# Test: Search for usage of RootLayout component
echo "Searching for RootLayout usage:"
rg --type ts --type tsx "<RootLayout"

Length of output: 306


Script:

#!/bin/bash
# Description: Verify the usage of RootLayout component using file extension globs

# Test: Search for imports of RootLayout
echo "Searching for RootLayout imports in .ts and .tsx files:"
rg "import\s+.*RootLayout\s+from\s+.*layout" --glob "*.ts" --glob "*.tsx"

# Test: Search for usage of RootLayout component
echo "Searching for RootLayout usage in .ts and .tsx files:"
rg "<RootLayout" --glob "*.ts" --glob "*.tsx"

Length of output: 513

examples/example-vite-kitchen-sink/src/components/ui/label.tsx (3)

1-5: LGTM: Imports are appropriate and well-organized.

The imports cover all necessary dependencies for the component, including React, Radix UI's Label, and class-variance-authority. The use of a local utility import (@/lib/utils) is a good practice for code organization.


24-24: LGTM: Correct export statement.

The Label component is properly exported as a named export, following common React component export practices.


1-24: Great addition to the kitchen sink example. Remember to complete PR objectives.

This Label component is a well-structured and valuable addition to the kitchen sink example. It demonstrates good practices in using Radix UI, class-variance-authority, and React patterns.

As per the PR objectives, please ensure you:

  1. Add tests for this new component.
  2. Update relevant documentation.
  3. Create a dedicated CI job for the new examples.
  4. Complete a self-review of your code.

You can use the following script to check for the presence of test files:

This script will help verify if test files have been added for the Label component.

examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx (2)

5-5: LGTM! Type definition is well-defined.

The TextareaProps type is correctly defined and exported. It extends the standard HTML textarea attributes, which is a good practice for maintaining type safety and allowing all standard textarea props to be passed to the component.


23-23: LGTM! Export is correct.

The named export of the Textarea component is correct and follows common React patterns. This allows for easy and clear imports in other parts of the application.

examples/example-vite-kitchen-sink/src/dojo/models.ts (4)

1-1: LGTM: Import statement is correct and necessary.

The import of SchemaType from "@dojoengine/sdk" is appropriate for extending it in the OnchainDashSchemaType interface.


4-8: LGTM: GlobalCounter interface is well-structured.

The GlobalCounter interface is logically defined with appropriate types for its properties. It provides a clear structure for managing a global counter with an ordered field list and a unique identifier.


9-13: LGTM: CallerCounter interface is well-defined.

The CallerCounter interface is correctly structured with appropriate types for its properties. It provides a clear representation for managing caller-specific counters.


14-19: LGTM: OnchainDashSchemaType interface is well-structured and extends SchemaType correctly.

The OnchainDashSchemaType interface properly extends SchemaType and provides a logical structure for grouping related counters under the onchain_dash property. This design promotes good organization and type safety.

examples/example-vite-kitchen-sink/src/components/ui/input.tsx (4)

1-3: LGTM: Imports look good.

The imports are appropriate for a React component. The use of a local utility function cn is a good practice for managing class names.


5-5: LGTM: Type definition is well-defined.

The InputProps type effectively extends React's input HTML attributes, allowing the component to accept all standard input properties. This approach ensures type safety and component flexibility.


22-24: LGTM: Proper component naming and export.

The displayName is correctly set, which is helpful for debugging. The component is properly exported, making it available for use in other parts of the application.


1-24: Overall, excellent implementation with minor suggestions for improvement.

The Input component is well-implemented, type-safe, and follows React best practices. It provides a solid foundation for a consistent input style across the application.

However, considering the PR objectives:

  1. Documentation: Consider adding JSDoc comments to describe the component's purpose and usage.
  2. Tests: Add unit tests to ensure the component behaves as expected under various scenarios.
  3. CI Job: Ensure that this new example is included in the CI pipeline for the project.

To improve the overall architecture:

  1. Consider creating a constants.ts file to store shared CSS classes, making it easier to maintain consistent styling across components.
  2. If not already present, create an index.ts file in the components/ui directory to export all UI components, simplifying imports in other parts of the application.

To ensure this component is properly integrated into the kitchen sink example, run the following script:

This will help confirm that the new component is actually being utilized in the kitchen sink example as intended.

✅ Verification successful

Verified: Input component is correctly integrated into the kitchen sink example.

The Input component is successfully imported and utilized in components/header.tsx as shown:

  • examples/example-vite-kitchen-sink/src/components/header.tsx: <Input id="temperature" type="number" placeholder="0.4" />
  • examples/example-vite-kitchen-sink/src/components/header.tsx: <Input id="top-p" type="number" placeholder="0.7" />
  • examples/example-vite-kitchen-sink/src/components/header.tsx: <Input id="top-k" type="number" placeholder="0.0" />
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the Input component is imported and used in the kitchen sink example

# Test: Check if the Input component is imported in any file within the kitchen sink example
rg --type typescript 'import.*Input.*from.*components/ui/input' examples/example-vite-kitchen-sink/src

# Test: Check if the Input component is used in any file within the kitchen sink example
rg --type typescript '<Input' examples/example-vite-kitchen-sink/src

Length of output: 245


Script:

#!/bin/bash
# Description: Verify the Input component is imported and used in the kitchen sink example

# Test: Check if the Input component is imported in any file within the kitchen sink example
rg --type ts --type tsx 'import.*Input.*from.*components/ui/input' examples/example-vite-kitchen-sink/src

# Test: Check if the Input component is used in any file within the kitchen sink example
rg --type ts --type tsx '<Input' examples/example-vite-kitchen-sink/src

Length of output: 237


Script:

#!/bin/bash
# Description: Verify the Input component is imported and used in the kitchen sink example

# Test: Check if the Input component is imported in any file within the kitchen sink example
rg 'import\s+.*Input\s+from\s+"@/lib/utils"' --glob '*.ts' --glob '*.tsx' examples/example-vite-kitchen-sink/src

# Test: Check if the Input component is used in any file within the kitchen sink example
rg '<Input' --glob '*.ts' --glob '*.tsx' examples/example-vite-kitchen-sink/src

Length of output: 592

examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (2)

1-3: LGTM: Imports are appropriate and well-structured.

The imports are correctly defined and follow good practices:

  • Named imports for React hooks.
  • Separate imports for third-party libraries (lucide-react).
  • Local component import using an alias path.

5-6: LGTM: Component definition and initial state are well-structured.

The component is correctly defined as a default export, and the initial state is appropriately set using the useState hook. The default theme of 'light' is a common and user-friendly choice.

examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (1)

1-44: Overall, well-implemented StarknetProvider component.

This new StarknetProvider component is a solid addition to the kitchen sink example. It effectively wraps StarkNet blockchain interactions and follows React best practices. The use of environment variables for configuration provides good flexibility.

A few suggestions for improvement:

  1. Group imports for better readability.
  2. Optimize performance by moving provider and connector setup outside the component.
  3. Make the autoConnect behavior configurable for better flexibility.

These changes will enhance the component's performance and usability without altering its core functionality.

To ensure this component is properly integrated into the kitchen sink example, let's verify its usage:

This will help confirm that the StarknetProvider is being imported and used correctly in the kitchen sink example.

✅ Verification successful

StarknetProvider is correctly integrated into the kitchen sink example.

The StarknetProvider is properly imported and utilized in examples/example-vite-kitchen-sink/src/app/layout.tsx. This confirms that the component is effectively integrated and functions as intended within the kitchen sink example.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for StarknetProvider usage in the kitchen sink example

# Test: Search for StarknetProvider import and usage
rg --type typescript --type tsx "import.*StarknetProvider" examples/example-vite-kitchen-sink
rg --type typescript --type tsx "<StarknetProvider" examples/example-vite-kitchen-sink

Length of output: 254


Script:

#!/bin/bash
# Description: Check for StarknetProvider usage in the kitchen sink example

# Test: Search for StarknetProvider import and usage in .ts and .tsx files
rg -g "*.ts" -g "*.tsx" "import.*StarknetProvider" examples/example-vite-kitchen-sink
rg -g "*.ts" -g "*.tsx" "<StarknetProvider" examples/example-vite-kitchen-sink

Length of output: 362

examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx (2)

1-4: LGTM: Imports and utility functions are appropriate.

The import statements for React, Radix UI, and the utility function cn are correctly implemented and follow common practices for React component development.


28-28: LGTM: Component exports are correct.

All components (Tooltip, TooltipTrigger, TooltipContent, and TooltipProvider) are correctly exported as named exports. This allows for easy import and use of individual components in other parts of the application.

examples/example-vite-kitchen-sink/src/components/ui/badge.tsx (3)

6-24: Well-structured badge variants definition.

The badgeVariants definition using cva is well-structured and provides a good set of variants for the Badge component. The use of class-variance-authority allows for flexible and maintainable styling.


26-34: Well-structured Badge component.

The Badge component is well-structured, correctly utilizing the badgeVariants and allowing for additional className props. The use of the cn utility function for merging class names is a good practice.


1-4: Verify the cn utility function import.

The import of the cn utility function from @/lib/utils looks correct. However, it's important to ensure that this path is valid and the function is properly exported from that file.

Run the following script to verify the cn function import:

✅ Verification successful

cn utility function import verified successfully.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence and export of the `cn` function in the utils file.

# Test: Search for the `cn` function definition and export in the utils file.
fd --type f utils.ts --exec rg --type typescript -A 5 'export.*function cn'

Length of output: 287


Script:

#!/bin/bash
# Description: Verify the existence and export of the `cn` function in the utils file.

# Test: Search for the `cn` function definition and export in the utils file without specifying file type.
fd --type f utils.ts --exec rg -A 5 'export\s+function\s+cn'

Length of output: 388

examples/example-vite-kitchen-sink/src/components/ui/switch.tsx (3)

1-4: LGTM: Imports are appropriate and follow best practices.

The imports are well-organized, importing only the necessary modules. The use of the cn utility function from a local utils file is a good practice for managing class names, especially when using Tailwind CSS.


25-27: LGTM: Component display name and export are correctly implemented.

Setting the display name to the Radix UI Root's display name is a good practice for debugging and consistency. The use of a named export is appropriate for this component.


1-27: Overall, excellent implementation of the Switch component.

This new Switch component is a valuable addition to the kitchen sink example for the dojo.js project. It demonstrates good use of Radix UI primitives, React patterns, and Tailwind CSS for styling. The component is type-safe, customizable, and follows best practices for React development.

Regarding the PR objectives:

  1. The component contributes to the kitchen sink example as intended.
  2. Consider updating the PR description to mention this new Switch component specifically.
  3. Ensure that appropriate tests are added for this component.
  4. Update any relevant documentation to include information about this new Switch component.
  5. If a dedicated CI job for new examples is required, make sure it's set up to include this file.

Great work on implementing this component! The suggestions provided in the review comments can further enhance its extensibility and accessibility.

examples/example-vite-kitchen-sink/src/dojo/provider.tsx (2)

1-4: LGTM: Imports are well-organized and relevant.

The imports are appropriately structured, including necessary React hooks, custom types, and environment configurations. The use of a custom environment setup (@/env) is a good practice for managing configuration across different environments.


6-8: LGTM: Well-implemented custom hook.

The useDojoDb hook follows React conventions and provides a clean way to access the Dojo context throughout the application.

examples/example-vite-kitchen-sink/README.md (1)

3-19: Verify "Getting Started" instructions for dojo.js kitchen sink example

The current "Getting Started" instructions appear to be generic for a Next.js project. Please verify and update these instructions to be specific to the dojo.js kitchen sink example.

Consider including:

  1. Any prerequisite setup for dojo.js
  2. The correct command to run the kitchen sink example
  3. The correct URL to view the example (if different from http://localhost:3000)
  4. Any additional steps needed to explore the various features of the kitchen sink example
examples/example-vite-kitchen-sink/src/components/ui/button.tsx (2)

1-5: LGTM: Imports are appropriate and well-structured.

The imports cover all necessary dependencies for the Button component, including React, Radix UI's Slot for polymorphic capabilities, and class-variance-authority for styling. The local utility import cn is also included, which is likely used for class name composition.


56-56: LGTM: Appropriate exports.

Exporting both the Button component and the buttonVariants constant is a good practice. This allows consumers of the module to use the pre-defined button styles independently if needed, providing more flexibility in how the component can be used and extended.

examples/example-vite-kitchen-sink/tailwind.config.ts (2)

1-3: LGTM: Proper import and configuration declaration.

The import statement and configuration object declaration are correctly implemented using TypeScript.


54-58: LGTM: Flexible border radius configuration.

The border radius configuration uses CSS variables, which allows for easy customization and maintains consistency across the project.

examples/example-vite-kitchen-sink/src/app/globals.css (4)

1-3: Tailwind CSS directives are correctly implemented.

The Tailwind CSS directives are properly included in the correct order: base, components, and utilities. This ensures that Tailwind's styles are applied correctly throughout the project.


5-8: Body styles are well-defined using CSS custom properties.

The body styles are correctly implemented using CSS custom properties for colors. This approach enhances maintainability and allows for easy theme switching.


1-85: Overall, the globals.css file is well-structured and comprehensive.

This file successfully sets up a robust theming system using Tailwind CSS and custom properties. It provides a solid foundation for both light and dark modes, and follows best practices for CSS organization. The use of CSS custom properties for colors and fonts enhances maintainability and flexibility.

While there are a few minor suggestions for improvement (as noted in previous comments), the overall implementation is of high quality and suitable for a kitchen sink example.


10-14: Custom utility class for text balancing is a nice addition.

The .text-balance utility class is a good addition for improving text layout. However, it's important to note that text-wrap: balance; is a relatively new CSS feature.

To ensure browser compatibility, please run the following command:

Consider adding a fallback or progressive enhancement for browsers that don't support this feature.

examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (6)

1-4: LGTM: Imports are appropriate and well-structured.

The import statements are concise and relevant to the components being defined. The use of the 'vaul' library for Drawer primitives and the local 'cn' utility function are appropriate choices for this component.


6-15: LGTM: Drawer component is well-implemented.

The Drawer component is well-structured and follows React best practices. It effectively wraps the DrawerPrimitive.Root component, providing a clean API with sensible defaults. The use of rest props ensures flexibility, allowing users to pass additional props as needed.


23-33: LGTM: DrawerOverlay component is well-implemented.

The DrawerOverlay component is well-structured, using forwardRef for proper ref handling. The styling approach using the 'cn' utility function allows for easy customization while maintaining default styles. The displayName is correctly set, which aids in debugging.


56-76: LGTM: DrawerHeader and DrawerFooter components are well-implemented.

Both DrawerHeader and DrawerFooter components are cleanly implemented. They provide a consistent structure for the drawer's content, using the 'cn' utility function for flexible styling. The displayName properties are correctly set, aiding in debugging.


78-103: LGTM: DrawerTitle and DrawerDescription components are well-implemented.

Both DrawerTitle and DrawerDescription components are cleanly implemented using forwardRef. They properly wrap their respective DrawerPrimitive components and use the 'cn' utility function for flexible styling. The displayName properties are correctly set, which aids in debugging.


105-116: LGTM: Export statement is comprehensive and well-structured.

The export statement includes all the components defined in the file, allowing for easy and flexible importing of the Drawer components in other parts of the application.

examples/example-vite-kitchen-sink/src/app/page.tsx (2)

1-18: LGTM: Imports and component declaration look good.

The imports are appropriate for the component's functionality, and the Home component is correctly declared as a default export.


19-22: LGTM: State initialization and form setup are well-implemented.

The use of useState for managing the subscription state and useForm for form management are good practices. The useDojoDb hook is appropriately used to get the database instance.

examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (11)

1-5: LGTM: Import statements are well-organized and complete.

The import statements are logically organized, separating external libraries from local imports. All necessary components and utilities are imported.


7-7: LGTM: Dialog component is correctly defined.

The Dialog component is appropriately aliased to DialogPrimitive.Root, following a common pattern in React component libraries. This approach allows for easy renaming and potential future modifications if needed.


9-9: LGTM: DialogTrigger component is correctly defined.

The DialogTrigger component is appropriately aliased to DialogPrimitive.Trigger, maintaining consistency with the Dialog component definition. This approach provides flexibility for future customizations if needed.


11-11: LGTM: DialogPortal component is correctly defined.

The DialogPortal component is appropriately aliased to DialogPrimitive.Portal, maintaining consistency with the previous component definitions. This approach allows for potential future enhancements or modifications if needed.


13-13: LGTM: DialogClose component is correctly defined.

The DialogClose component is appropriately aliased to DialogPrimitive.Close, maintaining consistency with the previous component definitions. This approach provides flexibility for future customizations if needed.


54-66: LGTM: DialogHeader component is well-implemented.

The DialogHeader component is correctly implemented as a functional component. It uses the cn utility for flexible class name management and applies appropriate flex layout and spacing classes. The component's display name is set correctly.


68-80: LGTM: DialogFooter component is well-implemented.

The DialogFooter component is correctly implemented as a functional component. It uses the cn utility for flexible class name management and applies appropriate flex layout and responsive classes. The mobile-first approach with responsive classes is a good practice. The component's display name is set correctly.


82-95: LGTM: DialogTitle component is well-implemented.

The DialogTitle component is correctly implemented as a forward-ref component, wrapping DialogPrimitive.Title. It uses the cn utility for flexible class name management and applies appropriate typography-related classes for consistent styling. The component's display name is set correctly.


97-107: LGTM: DialogDescription component is well-implemented.

The DialogDescription component is correctly implemented as a forward-ref component, wrapping DialogPrimitive.Description. It uses the cn utility for flexible class name management and applies appropriate typography and color classes for consistent styling. The component's display name is set correctly.


109-120: LGTM: Export statement is comprehensive and well-organized.

The export statement includes all defined components, allowing for easy importing of multiple components in other files. This approach is clean and maintainable.


1-120: Overall, excellent implementation of the Dialog component and its subcomponents.

This file demonstrates a well-structured and comprehensive implementation of a Dialog component using React and Radix UI primitives. The code follows React best practices, makes effective use of forward refs, and provides a flexible and accessible dialog solution.

Key strengths:

  1. Consistent use of the cn utility for flexible class name management.
  2. Proper implementation of accessibility features.
  3. Effective use of React.forwardRef for component composition.
  4. Comprehensive animations and styling for a polished user experience.

Main suggestions for improvement:

  1. Consider breaking down long className strings for improved readability, especially in the DialogOverlay and DialogContent components.
  2. Extract the close button in DialogContent into a separate component for better modularity.

These minor improvements will further enhance the maintainability and readability of an already solid implementation.

examples/example-vite-kitchen-sink/src/components/ui/select.tsx (9)

7-11: Component assignments are correct

The components Select, SelectGroup, and SelectValue are correctly assigned from SelectPrimitive.


13-31: SelectTrigger component is well-implemented

The SelectTrigger component correctly utilizes React.forwardRef to forward refs. It merges class names using the cn utility function and properly handles props and children. The inclusion of the ChevronDown icon enhances the user interface.


33-49: SelectScrollUpButton component is correctly implemented

The SelectScrollUpButton component correctly forwards refs and spreads additional props. It uses the cn utility to combine class names and includes the ChevronUp icon for user interaction.


50-67: SelectScrollDownButton component is correctly implemented

The SelectScrollDownButton component mirrors the implementation of SelectScrollUpButton, correctly handling refs, props, and class names. It includes the ChevronDown icon, providing intuitive scrolling cues to the user.


68-98: SelectContent component is well-structured

The SelectContent component effectively handles the position prop with a default of "popper" and conditionally applies class names based on its value. It correctly integrates SelectScrollUpButton, SelectViewport, and SelectScrollDownButton to manage the dropdown content and scrolling functionality.


100-110: SelectLabel component is correctly implemented

The SelectLabel component properly forwards refs and spreads props. It utilizes the cn utility for class names, ensuring consistent styling.


112-133: SelectItem component is well-implemented

The SelectItem component correctly handles refs and props, and it integrates the SelectPrimitive.ItemIndicator with the Check icon to indicate selected items. The structure ensures accessibility and usability within the dropdown.


135-145: SelectSeparator component is correctly implemented

The SelectSeparator component effectively forwards refs, handles additional props, and applies appropriate class names for visual separation within the dropdown menu.


147-158: Export statements are comprehensive

All components are appropriately exported, ensuring they are accessible for use throughout the application.

examples/example-vite-kitchen-sink/src/components/sidebar.tsx (1)

179-207: Verify the appropriate use of DialogDescription for modal content

You are using DialogDescription to wrap interactive elements like buttons within the modal. Typically, DialogDescription is intended for descriptive text. Consider verifying if this is the correct component to use according to your UI library's guidelines.

If needed, replace DialogDescription with a more suitable container, such as a div or a dedicated content component provided by the library.

Comment on lines +1 to +3
{
"extends": ["next/core-web-vitals", "next/typescript"]
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

⚠️ Potential issue

ESLint configuration appears unused and inconsistent with project setup

The ESLint configuration in examples/example-vite-kitchen-sink/.eslintrc.json extends Next.js-specific rules. However, ESLint does not seem to be utilized in this project:

  • No ESLint dependencies are listed in package.json.
  • No ESLint scripts are defined in package.json.

Consider either removing the ESLint configuration if linting is not required or properly integrating ESLint by adding the necessary dependencies and scripts aligned with the Vite and Dojo.js setup.

🔗 Analysis chain

Revise ESLint configuration for consistency with project setup

The current ESLint configuration extends Next.js-specific rules, which seems inconsistent with a Vite-based Dojo.js project. This could lead to irrelevant linting rules and potential conflicts. Consider the following suggestions:

  1. Replace Next.js configurations with more appropriate ones for a Vite and Dojo.js project. For example:

    • Use eslint:recommended as a base.
    • Add plugin:@typescript-eslint/recommended for TypeScript support.
    • Include any Dojo.js specific ESLint plugins or configurations if available.
  2. Add custom rules or overrides that are specific to your kitchen sink example.

  3. Consider adding a comment explaining the purpose of this configuration file for the kitchen sink example.

Here's a suggested revision:

{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "plugins": ["@typescript-eslint"],
  "rules": {
    // Add any custom rules here
  },
  "overrides": [
    // Add any specific overrides for the kitchen sink example
  ]
}

Don't forget to install the necessary ESLint plugins for this configuration.

To ensure we're using the correct ESLint configuration for this project, let's check for any existing ESLint configurations and the project's package.json:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
echo "Searching for ESLint configurations:"
fd -e json -e js -e yaml -e yml --glob '*eslint*'
echo "\nChecking package.json for ESLint related dependencies:"
jq '.dependencies + .devDependencies | with_entries(select(.key | test("eslint")))' package.json

Length of output: 408


Script:

#!/bin/bash
echo "Inspecting package.json scripts for ESLint usage:"
jq '.scripts | to_entries[] | select(.value | test("eslint")) | {script: .key, command: .value}' package.json

Length of output: 220

.gitmodules Outdated
Comment on lines 4 to 6
path = examples/example-vite-kitchen-sink/src/onchain
url = https://github.com/MartianGreed/onchain-dash
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Submodule Documentation Missing

The new submodule examples/example-vite-kitchen-sink/src/onchain does not include a README.md file. Adding documentation is essential to:

  • Explain the purpose and functionality of the onchain-dash repository.
  • Assist future developers in understanding and maintaining the submodule.
  • Ensure clarity in how the submodule integrates with the kitchen sink example.

Please add a README.md to the submodule repository or provide the necessary documentation within the project to address this gap.

🔗 Analysis chain

Review the new submodule configuration and its implications.

The new submodule configuration is correctly formatted and aligns with the PR objective of adding a kitchen sink example. However, there are a few points to consider:

  1. The submodule points to a personal repository (https://github.com/MartianGreed/onchain-dash). This might raise concerns about long-term maintenance and ownership. Consider moving this repository under the project's organization for better continuity and access control.

  2. The name "onchain-dash" doesn't clearly indicate its relationship to the kitchen sink example or the dojo.js project. It would be helpful to provide more context about the purpose and content of this repository.

  3. Remember to update the project documentation to reflect this new submodule and its purpose within the kitchen sink example.

  4. Please ensure that all items in the PR checklist are completed, including updating documentation, adding tests, and creating a dedicated CI job for the new examples.

To better understand the content and purpose of the new submodule, let's examine its structure:

This will help us verify the contents and documentation of the new submodule.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Examine the structure of the new submodule

# Test: List the contents of the new submodule directory
echo "Contents of the new submodule directory:"
ls -R examples/example-vite-kitchen-sink/src/onchain

# Test: Check for a README file in the submodule
echo -e "\nChecking for README file:"
cat examples/example-vite-kitchen-sink/src/onchain/README.md 2>/dev/null || echo "README.md not found"

Length of output: 372

Comment on lines 1 to 15
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import RootLayout from "./app/layout";
import Home from "./app/page";

import "./app/globals.css";

createRoot(document.getElementById("root")!).render(
<StrictMode>
<RootLayout>
<Home />
</RootLayout >
</StrictMode >
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance the educational value of the kitchen sink example.

While the current implementation is correct and follows best practices, consider the following suggestions to improve the educational value of this kitchen sink example:

  1. Add comments explaining the purpose of each import and component. This will help developers understand the structure and purpose of the example.

  2. Consider implementing an error boundary to demonstrate error handling in React applications.

  3. You might want to showcase more React features or patterns in this main file, such as context providers or custom hooks, to make it a more comprehensive example.

Here's an example of how you could add explanatory comments:

// Import core React components
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

// Import custom components
import RootLayout from "./app/layout";
import Home from "./app/page";

// Import global styles
import "./app/globals.css";

// Create and render the React application
const rootElement = document.getElementById("root");
if (rootElement) {
  createRoot(rootElement).render(
    // StrictMode helps identify potential problems in the application
    <StrictMode>
      {/* RootLayout provides common layout elements */}
      <RootLayout>
        {/* Home is the main content of the application */}
        <Home />
      </RootLayout>
    </StrictMode>
  );
} else {
  console.error("Root element not found");
}

Comment on lines 1 to 13
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance the example to be a more comprehensive kitchen sink demonstration.

While the current structure is correct for a basic Vite + React + TypeScript project, consider the following suggestions to make it a more comprehensive kitchen sink example:

  1. Add comments explaining the purpose of each section and how it relates to the dojo.js project.
  2. Include placeholder elements or components that demonstrate various features of dojo.js.
  3. Consider adding CSS links or inline styles to showcase styling capabilities.
  4. Implement accessibility features like ARIA attributes on the root div.

Here's a suggested enhancement:

 <!doctype html>
 <html lang="en">
     <head>
         <meta charset="UTF-8" />
         <link rel="icon" type="image/svg+xml" href="/vite.svg" />
         <meta name="viewport" content="width=device-width, initial-scale=1.0" />
         <title>Kitchen Sink Example - Vite + React + TS with dojo.js</title>
         <meta name="description" content="A comprehensive kitchen sink example showcasing Vite, React, TypeScript, and dojo.js capabilities." />
+        <link rel="stylesheet" href="/src/styles/main.css">
     </head>
     <body>
-        <div id="root"></div>
+        <!-- Main application container with ARIA role -->
+        <div id="root" role="main" aria-label="dojo.js Kitchen Sink Example"></div>
+        <!-- Fallback content for non-JS environments -->
+        <noscript>You need to enable JavaScript to run this dojo.js example.</noscript>
         <script type="module" src="/src/main.tsx"></script>
     </body>
 </html>

Additionally, ensure that the main.tsx file includes examples of various dojo.js features and components.

Committable suggestion was skipped due to low confidence.

Comment on lines +6 to +12
"tailwind": {
"config": "tailwind.config.ts",
"css": "app/globals.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

CSS file not found and missing Vite configuration.

The Tailwind configuration references a CSS file at app/globals.css, which does not exist in the repository. Additionally, no Vite configuration file was found in the root directory.

  • Verify and correct the CSS file path in the Tailwind configuration or ensure that app/globals.css is added to the project.
  • Add a Vite configuration file (e.g., vite.config.ts) to the root directory to ensure proper project setup and compatibility with Vite.
🔗 Analysis chain

Verify CSS file path and consider adding a prefix.

The Tailwind configuration looks good overall, but there are two points to consider:

  1. The CSS file path "app/globals.css" suggests a Next.js-like structure. Verify if this path is correct for a Vite project, as Vite typically uses a different directory structure.

  2. The prefix is currently empty. While this is valid, consider adding a prefix (e.g., "djs-" for dojo.js) to avoid potential class name conflicts, especially in larger projects or when integrating with other libraries.

To verify the CSS file path, run the following script:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the specified CSS file exists and search for alternative locations if not found.

# Test: Check if the specified CSS file exists
if [ -f "app/globals.css" ]; then
    echo "The specified CSS file exists at app/globals.css"
else
    echo "The specified CSS file was not found at app/globals.css"
    echo "Searching for alternative locations:"
    fd -e css -d 3
fi

Length of output: 320


Script:

#!/bin/bash
# Description: Verify the existence of the specified CSS file and check for Vite configuration.

# Check if the specified CSS file exists
if [ -f "app/globals.css" ]; then
    echo "The specified CSS file exists at app/globals.css"
else
    echo "The specified CSS file was not found at app/globals.css"
    echo "Searching for alternative CSS file locations:"
    fd -e css -d 3
fi

# Check for Vite configuration files in the root directory
vite_config=$(fd -e js -e ts 'vite.config' -d 1)
if [ -n "$vite_config" ]; then
    echo "Vite configuration file found: $vite_config"
else
    echo "No Vite configuration file found in the root directory."
fi

Length of output: 454

Comment on lines 134 to 146
<Label htmlFor="role">Role</Label>
<Select defaultValue="system">
<SelectTrigger>
<SelectValue placeholder="Select a role" />
</SelectTrigger>
<SelectContent>
<SelectItem value="system">System</SelectItem>
<SelectItem value="user">User</SelectItem>
<SelectItem value="assistant">Assistant</SelectItem>
</SelectContent>
</Select>
</div>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Accessibility issue: Label not properly associated with the select component

Similarly, the <Label htmlFor="role"> should be associated with the role selection, but there is no matching id="role" on the select component or its children.

Consider adding id="role" to the <Select> component to ensure proper association:

- <Select defaultValue="system">
+ <Select id="role" defaultValue="system">
📝 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
<Label htmlFor="role">Role</Label>
<Select defaultValue="system">
<SelectTrigger>
<SelectValue placeholder="Select a role" />
</SelectTrigger>
<SelectContent>
<SelectItem value="system">System</SelectItem>
<SelectItem value="user">User</SelectItem>
<SelectItem value="assistant">Assistant</SelectItem>
</SelectContent>
</Select>
</div>
<Label htmlFor="role">Role</Label>
<Select id="role" defaultValue="system">
<SelectTrigger>
<SelectValue placeholder="Select a role" />
</SelectTrigger>
<SelectContent>
<SelectItem value="system">System</SelectItem>
<SelectItem value="user">User</SelectItem>
<SelectItem value="assistant">Assistant</SelectItem>
</SelectContent>
</Select>
</div>

Comment on lines 157 to 162
<Tooltip>
<Dialog modal={modalEnabled} open={modalOpen} onOpenChange={setModalOpen}>
<TooltipTrigger asChild>
<DialogTrigger asChild>
<Button
variant="ghost"
size="icon"
className="mt-auto rounded-lg"
aria-label="Help"
>
<SquareUser className="size-5" />
</Button>
</DialogTrigger>
</TooltipTrigger>
<TooltipContent side="right" sideOffset={5}>
Account
</TooltipContent>

<DialogContent>
<DialogHeader>
<DialogTitle>Choose the wallet you want to use</DialogTitle>
</DialogHeader>
<DialogDescription className="grid gap-2 p-4">
{connectors.map((connector) => {
return (
<Button
key={connector.id}
onClick={() => connect(connector)}
variant="secondary"
className="relative pl-12 flex"
>
<div className="absolute left-2 top-1/2 flex size-8 -translate-y-1/2 items-center justify-center rounded-xs bg-background">
<img
src={
connector.icon.dark
}
className="size-5"
alt={`${connector.name}`}
/>
</div>
{walletIdToName.get(connector.id) ?? connector.name}
{isWalletConnecting(connector.id) && (
<Loader
className="absolute right-2.5 top-3 animate-spin"
size={24}
/>
)}
</Button>
);
})}
</DialogDescription>
</DialogContent>
</Dialog>
</Tooltip>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify the nesting of Tooltip and Dialog components

The current nesting of Tooltip, TooltipTrigger, Dialog, and DialogTrigger components is complex and may lead to unintended behavior or rendering issues. Consider refactoring the component hierarchy to enhance readability and maintainability.

You could restructure the components as follows:

  • Use the DialogTrigger directly within the TooltipTrigger to reduce nesting.
  • Ensure that the TooltipContent correctly references the trigger for proper tooltip behavior.

Example refactored structure:

<Tooltip>
  <TooltipTrigger asChild>
    <Dialog>
      <DialogTrigger asChild>
        <Button
          variant="ghost"
          size="icon"
          className="mt-auto rounded-lg"
          aria-label="Account"
        >
          <SquareUser className="size-5" />
        </Button>
      </DialogTrigger>
      {/* DialogContent here */}
    </Dialog>
  </TooltipTrigger>
  <TooltipContent side="right" sideOffset={5}>
    Account
  </TooltipContent>
</Tooltip>

Comment on lines +189 to +147
<img
src={
connector.icon.dark
}
className="size-5"
alt={`${connector.name}`}
/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential undefined connector.icon.dark to prevent broken images

There's a possibility that connector.icon.dark could be undefined, resulting in a broken image source. To enhance robustness, consider providing a fallback icon or conditionally rendering the img tag only when the icon is available.

You can modify the code as follows:

{connector.icon.dark ? (
  <img
    src={connector.icon.dark}
    className="size-5"
    alt={`${connector.name}`}
  />
) : (
  <DefaultIcon className="size-5" />
)}

Ensure you import or define a DefaultIcon component to use as a placeholder when the icon is not available.

Comment on lines +45 to +40
} catch (error) {
setModalOpen(true);
setModalEnabled(true);
console.error(error);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Provide user feedback upon connection errors

When a connection error occurs, the error is logged to the console, and the modal remains open. To improve user experience, consider displaying an error message within the modal to inform the user that the connection attempt failed.

You might modify the connect function to set an error state and render the error message in the modal:

const [connectError, setConnectError] = useState<string | null>(null);

const connect = useCallback(async (connector: Connector) => {
  setModalEnabled(false);
  setPendingConnectorId(connector.id);
  setConnectError(null);
  try {
    await connectAsync({ connector });
    setModalOpen(false);
  } catch (error) {
    setModalOpen(true);
    setModalEnabled(true);
    setConnectError('Failed to connect. Please try again.');
    console.error(error);
  }
  setPendingConnectorId(undefined);
}, [connectAsync, setModalOpen]);

Then, display the error message within your modal content:

{connectError && (
  <p className="text-red-500">{connectError}</p>
)}

variant="ghost"
size="icon"
className="mt-auto rounded-lg"
aria-label="Help"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct the aria-label for the Account button

The aria-label for the Account button is incorrectly set to "Help". It should be "Account" to accurately describe the button's purpose for accessibility.

Apply this diff to fix the aria-label:

-                      aria-label="Help"
+                      aria-label="Account"
📝 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
aria-label="Help"
aria-label="Account"

Copy link

@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: 3

🧹 Outside diff range and nitpick comments (5)
examples/example-vite-kitchen-sink/src/lib/utils.ts (1)

25-63: LGTM with minor suggestions: Comprehensive accent removal

The accentsToAscii function provides a solid implementation for removing accents from characters. It covers a wide range of common accented characters and effectively uses the transliterate function.

Suggestions for minor improvements:

  1. Consider moving the charMap outside the function to avoid recreating it on each call:
const accentCharMap: Record<string, string> = {
  á: "a",
  ú: "u",
  // ... (rest of the map)
};

function accentsToAscii(str: string): string {
  return transliterate(str, accentCharMap);
}
  1. If a more comprehensive character set is needed, consider using a library like unidecode or diacritics that covers a wider range of Unicode characters.

These suggestions are optional and depend on the specific requirements of your project.

examples/example-vite-kitchen-sink/src/app/page.tsx (2)

58-60: Enhance accessibility of the main element.

To improve accessibility, consider adding an aria-label to the <main> element to describe its purpose. For example:

<main className="grid flex-1 gap-4 overflow-auto p-4 md:grid-cols-2 lg:grid-cols-3" aria-label="Dashboard">

This will help screen reader users understand the content of this section more easily.


73-80: Implement actual stats in the Stats section.

The Stats section currently contains placeholder text. Consider implementing actual statistics about the application's state or usage. This could include:

  • Total number of messages sent
  • Number of active users
  • Most active user
  • Any other relevant metrics

Would you like me to suggest a structure for displaying these stats or help create a new component for this purpose?

examples/example-vite-kitchen-sink/src/components/chat.tsx (2)

13-40: LGTM: Well-structured typed data generation.

The generateTypedData function correctly structures the typed data for StarkNet message signing. It includes all necessary components such as types, domain information, and message details.

Consider adding a type annotation for the return value to improve code readability and type safety. For example:

function generateTypedData(identity: string, content: string, timestamp: number = Date.now()): TypedData {
  // ... existing implementation ...
}

This change would make the function's return type explicit and consistent with its usage in the Chat component.


64-92: Consider adding loading state and disabling the submit button when appropriate.

To improve user experience, consider adding a loading state to the form submission process and disabling the submit button while the message is being signed and published.

Here's a suggested improvement for the form:

const [isSubmitting, setIsSubmitting] = useState(false);

const publish = useCallback(async (data) => {
  setIsSubmitting(true);
  try {
    // ... existing publish logic ...
  } catch (error) {
    // ... error handling ...
  } finally {
    setIsSubmitting(false);
  }
}, [db, account]);

return (
  <form ... >
    {/* ... existing form elements ... */}
    <Button 
      size="sm" 
      className="ml-auto gap-1.5" 
      disabled={isSubmitting || !account}
    >
      {isSubmitting ? 'Sending...' : 'Send Message'}
      <CornerDownLeft className="size-3.5" />
    </Button>
  </form>
);

This change will provide better visual feedback to the user during the message submission process.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f4bd1d7 and 54516e5.

⛔ Files ignored due to path filters (4)
  • examples/example-vite-kitchen-sink/src/app/favicon.ico is excluded by !**/*.ico
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistMonoVF.woff is excluded by !**/*.woff
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistVF.woff is excluded by !**/*.woff
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (40)
  • .gitmodules (1 hunks)
  • examples/example-vite-kitchen-sink/.env.dist (1 hunks)
  • examples/example-vite-kitchen-sink/.eslintrc.json (1 hunks)
  • examples/example-vite-kitchen-sink/.gitignore (1 hunks)
  • examples/example-vite-kitchen-sink/README.md (1 hunks)
  • examples/example-vite-kitchen-sink/components.json (1 hunks)
  • examples/example-vite-kitchen-sink/index.html (1 hunks)
  • examples/example-vite-kitchen-sink/package.json (1 hunks)
  • examples/example-vite-kitchen-sink/postcss.config.mjs (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/globals.css (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/layout.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/page.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/chat.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/header.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/models.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/env.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/lib/utils.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/main.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/onchain (1 hunks)
  • examples/example-vite-kitchen-sink/tailwind.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/tsconfig.json (1 hunks)
  • examples/example-vite-kitchen-sink/vite.config.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • examples/example-vite-kitchen-sink/src/onchain
🚧 Files skipped from review as they are similar to previous changes (35)
  • .gitmodules
  • examples/example-vite-kitchen-sink/.env.dist
  • examples/example-vite-kitchen-sink/.eslintrc.json
  • examples/example-vite-kitchen-sink/.gitignore
  • examples/example-vite-kitchen-sink/README.md
  • examples/example-vite-kitchen-sink/components.json
  • examples/example-vite-kitchen-sink/index.html
  • examples/example-vite-kitchen-sink/package.json
  • examples/example-vite-kitchen-sink/postcss.config.mjs
  • examples/example-vite-kitchen-sink/src/app/globals.css
  • examples/example-vite-kitchen-sink/src/app/layout.tsx
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/header.tsx
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx
  • examples/example-vite-kitchen-sink/src/dojo.config.ts
  • examples/example-vite-kitchen-sink/src/dojo/models.ts
  • examples/example-vite-kitchen-sink/src/env.ts
  • examples/example-vite-kitchen-sink/src/main.tsx
  • examples/example-vite-kitchen-sink/tailwind.config.ts
  • examples/example-vite-kitchen-sink/tsconfig.json
  • examples/example-vite-kitchen-sink/vite.config.ts
🧰 Additional context used
🪛 Biome
examples/example-vite-kitchen-sink/src/dojo/provider.tsx

[error] 12-14: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

examples/example-vite-kitchen-sink/src/lib/utils.ts

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

🔇 Additional comments (12)
examples/example-vite-kitchen-sink/src/dojo/provider.tsx (4)

1-8: LGTM: Imports and custom hook are well-structured.

The imports cover all necessary dependencies, and the useDojoDb custom hook provides a clean way to access the Dojo context throughout the application.


10-14: Replace empty interface with type alias.

The DojoProviderProps interface is currently empty, which doesn't provide any value. It's better to use a type alias in this case.

Replace the empty interface with a type alias:

-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-interface DojoProviderProps {
-}
+type DojoProviderProps = Record<string, never>;

This change addresses the static analysis warning and improves code clarity.

🧰 Tools
🪛 Biome

[error] 12-14: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


15-16: LGTM: Component declaration and state initialization are correct.

The DojoProvider component is well-structured with proper typing for its props, including the children prop. The db state is correctly initialized using useState.


40-45: LGTM: Provider component's return statement is correct.

The DojoProvider component correctly wraps its children with the DojoContext.Provider, passing the db state as the context value. This structure ensures that all child components have access to the initialized Dojo SDK instance.

examples/example-vite-kitchen-sink/src/lib/utils.ts (3)

4-6: LGTM: Efficient class name handling

The cn function effectively combines the power of clsx for conditional class names and twMerge for Tailwind CSS class merging. This is a solid approach for managing dynamic class names in React components using Tailwind CSS.


18-23: LGTM: Efficient character transliteration

The transliterate function is well-implemented. It efficiently maps characters using the provided character map, falling back to the original character if no mapping is found. This approach is both concise and performant.


65-68: LGTM: Comprehensive ASCII conversion

The toValidAscii function provides a robust approach to converting strings to valid ASCII:

  1. It uses normalize("NFD") to decompose characters into their base form and combining characters.
  2. The regex /[\u0300-\u036f]/g effectively removes combining diacritical marks.
  3. The accentsToAscii function is applied for additional accent removal.

This combination of techniques ensures thorough accent removal and ASCII conversion.

Regarding the static analysis hint:
The warning about "Unexpected combined character in the character class" appears to be a false positive. The regex /[\u0300-\u036f]/g is a valid and common pattern for matching combining diacritical marks in Unicode.

🧰 Tools
🪛 Biome

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

examples/example-vite-kitchen-sink/src/app/page.tsx (2)

1-13: LGTM: Imports and component setup look good.

The imports are appropriate, and the component is set up correctly using React hooks. The use of useDojoDb and useState for managing the database instance and subscription state is well-implemented.


83-83: Verify Chat component integration.

The Chat component is included, but it's not clear if it requires any props or context from the parent component. Please verify if the Chat component needs access to the db instance or any other data from the Home component.

If needed, consider passing necessary props or wrapping the component in a context provider:

<Chat db={db} /> // If db is needed

or

<SomeContext.Provider value={someValue}>
  <Chat />
</SomeContext.Provider>

This will ensure that the Chat component has all the necessary data to function correctly within the dashboard.

examples/example-vite-kitchen-sink/src/components/chat.tsx (3)

1-11: LGTM: Imports are well-organized and relevant.

The imports are logically grouped and cover all necessary dependencies for the component's functionality.


43-46: LGTM: Well-structured React component with proper form handling.

The Chat component is well-organized and uses react-hook-form effectively for managing form state. The UI structure is clear and includes appropriate accessibility attributes.

Also applies to: 64-92


47-62: ⚠️ Potential issue

Consider improving error handling and completing the message publishing functionality.

The publish function has a good start with message signing, but there are a few areas for improvement:

  1. Error handling: The current implementation only logs errors to the console. Consider adding user-facing error messages or notifications.

  2. Message publishing: The code for publishing the message to the database is commented out. Ensure this functionality is implemented before considering the feature complete.

  3. Form reset: After successful message submission, consider resetting the form.

Here's a suggested improvement for the publish function:

const publish = useCallback(async (data) => {
  if (!account) {
    console.error("No account connected");
    // TODO: Show user-facing error message
    return;
  }

  try {
    const asciiMessage = toValidAscii(data.message);
    const msg = generateTypedData(account.address, asciiMessage);
    const signature = await account.signMessage(msg as TypedData);
    
    // TODO: Uncomment and implement message publishing
    // await db.client.publishMessage(JSON.stringify(msg), [signature.r, signature.s]);
    
    console.log("Message signed successfully:", signature);
    // TODO: Show success message to user
    // TODO: Reset form
  } catch (error) {
    console.error("Failed to sign or publish message:", error);
    // TODO: Show error message to user
  }
}, [db, account]);

To ensure that the db.client.publishMessage method exists and is implemented correctly, run the following script:

Comment on lines 17 to 39
useEffect(() => {
if (db === null && undefined !== window) {
import("@dojoengine/sdk").then(({ init }) => {
init<OnchainDashSchemaType>(
{
client: {
rpcUrl: getRpcUrl(),
toriiUrl: env.VITE_TORII_URL,
relayUrl: "",
worldAddress: "0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12",
},
domain: {
name: "OnChainDash",
revision: "1",
},
},
schema
).then(setDb).catch(console.error);

});
}
}, [db, setDb])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider enhancing error handling in SDK initialization.

The SDK initialization logic is well-structured, but the error handling could be improved. Currently, errors are only logged to the console.

Consider implementing a more robust error handling mechanism:

  1. Create an error state to capture initialization errors.
  2. Display an error message to the user if initialization fails.
  3. Optionally, implement a retry mechanism.

Here's a suggested implementation:

 export default function DojoProvider({ children }: React.PropsWithChildren<DojoProviderProps>) {
   const [db, setDb] = useState<SDK<OnchainDashSchemaType> | null>(null);
+  const [error, setError] = useState<Error | null>(null);
+
+  const initializeSDK = () => {
+    import("@dojoengine/sdk").then(({ init }) => {
+      init<OnchainDashSchemaType>(
+        {
+          client: {
+            rpcUrl: getRpcUrl(),
+            toriiUrl: env.VITE_TORII_URL,
+            relayUrl: "",
+            worldAddress: "0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12",
+          },
+          domain: {
+            name: "OnChainDash",
+            revision: "1",
+          },
+        },
+        schema
+      ).then(setDb).catch(setError);
+    });
+  };
+
   useEffect(() => {
-    if (db === null && undefined !== window) {
-      import("@dojoengine/sdk").then(({ init }) => {
-        init<OnchainDashSchemaType>(
-          {
-            client: {
-              rpcUrl: getRpcUrl(),
-              toriiUrl: env.VITE_TORII_URL,
-              relayUrl: "",
-              worldAddress: "0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12",
-            },
-            domain: {
-              name: "OnChainDash",
-              revision: "1",
-            },
-          },
-          schema
-        ).then(setDb).catch(console.error);
-      });
+    if (db === null && error === null && typeof window !== 'undefined') {
+      initializeSDK();
     }
-  }, [db, setDb])
+  }, [db, error]);
+
+  if (error) {
+    return <div>Error initializing Dojo SDK: {error.message}</div>;
+  }

   return (
     <DojoContext.Provider value={db}>
       {children}
     </DojoContext.Provider >
   )
 }

This implementation provides better error handling and user feedback in case of initialization failures.

📝 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
useEffect(() => {
if (db === null && undefined !== window) {
import("@dojoengine/sdk").then(({ init }) => {
init<OnchainDashSchemaType>(
{
client: {
rpcUrl: getRpcUrl(),
toriiUrl: env.VITE_TORII_URL,
relayUrl: "",
worldAddress: "0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12",
},
domain: {
name: "OnChainDash",
revision: "1",
},
},
schema
).then(setDb).catch(console.error);
});
}
}, [db, setDb])
export default function DojoProvider({ children }: React.PropsWithChildren<DojoProviderProps>) {
const [db, setDb] = useState<SDK<OnchainDashSchemaType> | null>(null);
const [error, setError] = useState<Error | null>(null);
const initializeSDK = () => {
import("@dojoengine/sdk").then(({ init }) => {
init<OnchainDashSchemaType>(
{
client: {
rpcUrl: getRpcUrl(),
toriiUrl: env.VITE_TORII_URL,
relayUrl: "",
worldAddress: "0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12",
},
domain: {
name: "OnChainDash",
revision: "1",
},
},
schema
).then(setDb).catch(setError);
});
};
useEffect(() => {
if (db === null && error === null && typeof window !== 'undefined') {
initializeSDK();
}
}, [db, error]);
if (error) {
return <div>Error initializing Dojo SDK: {error.message}</div>;
}
return (
<DojoContext.Provider value={db}>
{children}
</DojoContext.Provider >
)
}

Comment on lines 14 to 54
useEffect(() => {
async function getEntities(db: SDK<OnchainDashSchemaType>) {
const sub = await db.subscribeEntityQuery(
{
onchain_dash: {
GlobalCounter: {
$: {},
},
CallerCounter: {
$: {}
}
},
},
(response) => {
if (response.error) {
console.error(
"Error querying todos and goals:",
response.error
);
return;
}
if (response.data) {
console.log(response.data)
}
}
);
setSubscription(sub)
}

if (db && !subscription) {
getEntities(db)
}

return () => {
if (subscription) {
if (subscription.free) {
subscription.free();
}
}
}
}, [db, subscription])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize useEffect and subscription logic.

The existing comment about updating the dependency array is still valid. Additionally, consider these optimizations:

  1. Move getEntities outside of useEffect and memoize it with useCallback.
  2. Use useRef for the subscription to avoid unnecessary re-renders.
  3. Simplify the dependency array.

Here's a suggested refactor:

const subscriptionRef = useRef<Subscription | null>(null);

const getEntities = useCallback(async (db: SDK<OnchainDashSchemaType>) => {
  const sub = await db.subscribeEntityQuery(
    // ... (existing subscription logic)
  );
  subscriptionRef.current = sub;
}, []);

useEffect(() => {
  if (db && !subscriptionRef.current) {
    getEntities(db);
  }

  return () => {
    if (subscriptionRef.current?.free) {
      subscriptionRef.current.free();
      subscriptionRef.current = null;
    }
  };
}, [db, getEntities]);

This refactor will optimize performance and prevent unnecessary re-renders.

Copy link

@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: 1

🧹 Outside diff range and nitpick comments (1)
examples/example-vite-kitchen-sink/src/lib/utils.ts (1)

25-63: LGTM: Comprehensive accent removal implementation

The accentsToAscii function provides a thorough mapping of accented characters to their ASCII equivalents. The implementation is clear and makes good use of the transliterate function.

Consider the following minor improvement:

To make the code more maintainable, you could consider moving the character map to a separate constant or configuration file. This would make it easier to update or extend the mapping in the future without modifying the function itself.

import { ACCENT_TO_ASCII_MAP } from './constants';

function accentsToAscii(str: string): string {
  return transliterate(str, ACCENT_TO_ASCII_MAP);
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 54516e5 and e699b8a.

⛔ Files ignored due to path filters (4)
  • examples/example-vite-kitchen-sink/src/app/favicon.ico is excluded by !**/*.ico
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistMonoVF.woff is excluded by !**/*.woff
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistVF.woff is excluded by !**/*.woff
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (40)
  • .gitmodules (1 hunks)
  • examples/example-vite-kitchen-sink/.env.dist (1 hunks)
  • examples/example-vite-kitchen-sink/.eslintrc.json (1 hunks)
  • examples/example-vite-kitchen-sink/.gitignore (1 hunks)
  • examples/example-vite-kitchen-sink/README.md (1 hunks)
  • examples/example-vite-kitchen-sink/components.json (1 hunks)
  • examples/example-vite-kitchen-sink/index.html (1 hunks)
  • examples/example-vite-kitchen-sink/package.json (1 hunks)
  • examples/example-vite-kitchen-sink/postcss.config.mjs (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/globals.css (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/layout.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/page.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/chat.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/header.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/models.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/env.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/lib/utils.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/main.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/onchain (1 hunks)
  • examples/example-vite-kitchen-sink/tailwind.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/tsconfig.json (1 hunks)
  • examples/example-vite-kitchen-sink/vite.config.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • examples/example-vite-kitchen-sink/src/onchain
🚧 Files skipped from review as they are similar to previous changes (37)
  • .gitmodules
  • examples/example-vite-kitchen-sink/.env.dist
  • examples/example-vite-kitchen-sink/.eslintrc.json
  • examples/example-vite-kitchen-sink/.gitignore
  • examples/example-vite-kitchen-sink/README.md
  • examples/example-vite-kitchen-sink/components.json
  • examples/example-vite-kitchen-sink/index.html
  • examples/example-vite-kitchen-sink/package.json
  • examples/example-vite-kitchen-sink/postcss.config.mjs
  • examples/example-vite-kitchen-sink/src/app/globals.css
  • examples/example-vite-kitchen-sink/src/app/layout.tsx
  • examples/example-vite-kitchen-sink/src/app/page.tsx
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/chat.tsx
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/header.tsx
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx
  • examples/example-vite-kitchen-sink/src/dojo.config.ts
  • examples/example-vite-kitchen-sink/src/dojo/models.ts
  • examples/example-vite-kitchen-sink/src/env.ts
  • examples/example-vite-kitchen-sink/src/main.tsx
  • examples/example-vite-kitchen-sink/tailwind.config.ts
  • examples/example-vite-kitchen-sink/tsconfig.json
  • examples/example-vite-kitchen-sink/vite.config.ts
🧰 Additional context used
🪛 Biome
examples/example-vite-kitchen-sink/src/dojo/provider.tsx

[error] 12-14: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

examples/example-vite-kitchen-sink/src/lib/utils.ts

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

🔇 Additional comments (9)
examples/example-vite-kitchen-sink/src/dojo/provider.tsx (5)

1-8: LGTM: Imports and custom hook are well-structured.

The imports cover all necessary dependencies, and the custom useDojoDb hook provides a clean way to access the Dojo context in other components.


10-11: LGTM: Context creation is appropriate.

The DojoContext is correctly created with a proper type definition, allowing for the initial null state.


40-45: LGTM: Context provider implementation is correct.

The DojoProvider component correctly wraps its children with the DojoContext.Provider, passing the db value. This follows the React context provider pattern and allows child components to access the Dojo database instance.


12-14: ⚠️ Potential issue

Replace empty interface with type alias.

As mentioned in a previous review, the empty DojoProviderProps interface doesn't provide any value. It's better to use a type alias in this case.

Replace the empty interface with a type alias:

-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-interface DojoProviderProps {
-}
+type DojoProviderProps = Record<string, never>;

This change addresses the static analysis warning and improves code clarity.

🧰 Tools
🪛 Biome

[error] 12-14: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


15-38: 🛠️ Refactor suggestion

Enhance error handling in SDK initialization.

As suggested in a previous review, the error handling in the SDK initialization can be improved. Currently, errors are only logged to the console.

Consider implementing a more robust error handling mechanism:

  1. Create an error state to capture initialization errors.
  2. Display an error message to the user if initialization fails.
  3. Optionally, implement a retry mechanism.

Here's a suggested implementation:

 export default function DojoProvider({ children }: React.PropsWithChildren<DojoProviderProps>) {
   const [db, setDb] = useState<SDK<OnchainDashSchemaType> | null>(null);
+  const [error, setError] = useState<Error | null>(null);
+
+  const initializeSDK = () => {
+    import("@dojoengine/sdk").then(({ init }) => {
+      init<OnchainDashSchemaType>(
+        {
+          client: {
+            rpcUrl: getRpcUrl(),
+            toriiUrl: env.VITE_TORII_URL,
+            relayUrl: "",
+            worldAddress: "0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12",
+          },
+          domain: {
+            name: "OnChainDash",
+            revision: "1",
+          },
+        },
+        schema
+      ).then(setDb).catch(setError);
+    });
+  };
+
   useEffect(() => {
-    if (db === null && undefined !== window) {
-      import("@dojoengine/sdk").then(({ init }) => {
-        init<OnchainDashSchemaType>(
-          {
-            client: {
-              rpcUrl: getRpcUrl(),
-              toriiUrl: env.VITE_TORII_URL,
-              relayUrl: "",
-              worldAddress: "0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12",
-            },
-            domain: {
-              name: "OnChainDash",
-              revision: "1",
-            },
-          },
-          schema
-        ).then(setDb).catch(console.error);
-      });
+    if (db === null && error === null && typeof window !== 'undefined') {
+      initializeSDK();
     }
-  }, [db, setDb])
+  }, [db, error]);
+
+  if (error) {
+    return <div>Error initializing Dojo SDK: {error.message}</div>;
+  }

   return (
     <DojoContext.Provider value={db}>
       {children}
     </DojoContext.Provider>
   )
 }

This implementation provides better error handling and user feedback in case of initialization failures.

examples/example-vite-kitchen-sink/src/lib/utils.ts (4)

4-6: LGTM: Efficient class name merging implementation

The cn function effectively combines the power of clsx for class name concatenation and twMerge for Tailwind CSS class deduplication. This is a well-established pattern for managing complex class combinations in Tailwind CSS projects.


18-23: LGTM: Efficient character transliteration implementation

The transliterate function provides a clean and efficient way to map characters based on a provided character map. Its implementation using array methods is concise and easy to understand.


1-68: Summary: Solid utility functions implementation with room for minor improvements

Overall, this file provides a set of well-implemented utility functions that cover class name merging, Stark felt handling, and string normalization. The code is generally clean, efficient, and follows good practices.

Key points:

  1. The cn function effectively combines clsx and twMerge for Tailwind CSS class management.
  2. The ensureStarkFelt function could benefit from improved input validation and error handling.
  3. The string normalization functions (transliterate, accentsToAscii, and toValidAscii) are well-implemented and comprehensive.

Consider addressing the suggested improvements, particularly for the ensureStarkFelt function, to enhance the robustness and maintainability of these utilities.

🧰 Tools
🪛 Biome

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)


65-68: LGTM: Effective ASCII normalization implementation

The toValidAscii function effectively combines Unicode normalization, regex-based diacritic removal, and custom accent transliteration to produce a valid ASCII representation of the input string.

Regarding the static analysis hint about the character class on line 67:

The regex /[\u0300-\u036f]/g is a standard way to match combining diacritical marks in Unicode. The static analysis tool's warning appears to be a false positive. This regex is correct and widely used for removing diacritical marks after NFD normalization.

To verify the correctness of this implementation, you can run the following test:

This test will help ensure that the function correctly handles various accented characters and diacritical marks.

🧰 Tools
🪛 Biome

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

Copy link

@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 and nitpick comments (6)
examples/example-vite-kitchen-sink/README.md (2)

25-25: Consider adding a note about API key acquisition

The command for starting torii with mainnet/sepolia includes a placeholder for an API key. It would be helpful to add a brief note or link on how to obtain this API key, ensuring users can successfully set up the project for mainnet/sepolia usage.


48-49: Consider providing more detailed information about manual updates

The notes section mentions important manual updates that users might need to perform. To improve clarity and user experience, consider expanding on these points:

  1. Explain why and when users might need to update the actions contract address.
  2. Provide more context about deploying classes for wallet compatibility. What are the steps involved? Are there any resources or documentation that users can refer to for this process?

Adding this information will help users better understand and execute these manual steps if needed.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~48-~48: You might be missing the article “the” here.
Context: ... ### Notes - you main want to updateactionscontract address insrc/compon...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

examples/example-vite-kitchen-sink/src/components/chat.tsx (4)

1-11: Consider using consistent import paths.

The import statements use a mix of relative (./ui/badge) and absolute (@/dojo/provider) paths. For better maintainability and consistency, consider standardizing the import path style throughout the file.


13-41: Consider explicit timestamp handling.

The generateTypedData function uses Date.now() as a default value for the timestamp parameter. This approach might lead to inconsistencies between the time of function call and actual message creation. Consider passing the timestamp explicitly from the caller to ensure consistency.


22-26: Reconsider the hyphenated type name.

The type name "onchain_dash-Message" contains a hyphen, which might cause issues in some contexts, especially if this type name is used in generated code or APIs. Consider using a consistent naming convention, such as camelCase or snake_case (e.g., "onchain_dash_Message" or "OnchainDashMessage").


67-68: Remove commented-out code.

The commented-out code at lines 67-68 should be removed if it's no longer needed. Keeping unused code can lead to confusion and maintenance issues.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between e699b8a and a8ca98a.

⛔ Files ignored due to path filters (4)
  • examples/example-vite-kitchen-sink/src/app/favicon.ico is excluded by !**/*.ico
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistMonoVF.woff is excluded by !**/*.woff
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistVF.woff is excluded by !**/*.woff
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (40)
  • .gitmodules (1 hunks)
  • examples/example-vite-kitchen-sink/.env.dist (1 hunks)
  • examples/example-vite-kitchen-sink/.eslintrc.json (1 hunks)
  • examples/example-vite-kitchen-sink/.gitignore (1 hunks)
  • examples/example-vite-kitchen-sink/README.md (1 hunks)
  • examples/example-vite-kitchen-sink/components.json (1 hunks)
  • examples/example-vite-kitchen-sink/index.html (1 hunks)
  • examples/example-vite-kitchen-sink/package.json (1 hunks)
  • examples/example-vite-kitchen-sink/postcss.config.mjs (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/globals.css (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/layout.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/page.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/chat.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/header.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/models.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/env.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/lib/utils.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/main.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/onchain (1 hunks)
  • examples/example-vite-kitchen-sink/tailwind.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/tsconfig.json (1 hunks)
  • examples/example-vite-kitchen-sink/vite.config.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • examples/example-vite-kitchen-sink/src/onchain
🚧 Files skipped from review as they are similar to previous changes (35)
  • .gitmodules
  • examples/example-vite-kitchen-sink/.env.dist
  • examples/example-vite-kitchen-sink/.eslintrc.json
  • examples/example-vite-kitchen-sink/.gitignore
  • examples/example-vite-kitchen-sink/components.json
  • examples/example-vite-kitchen-sink/index.html
  • examples/example-vite-kitchen-sink/package.json
  • examples/example-vite-kitchen-sink/postcss.config.mjs
  • examples/example-vite-kitchen-sink/src/app/globals.css
  • examples/example-vite-kitchen-sink/src/app/layout.tsx
  • examples/example-vite-kitchen-sink/src/app/page.tsx
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/header.tsx
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx
  • examples/example-vite-kitchen-sink/src/dojo.config.ts
  • examples/example-vite-kitchen-sink/src/dojo/models.ts
  • examples/example-vite-kitchen-sink/src/env.ts
  • examples/example-vite-kitchen-sink/src/main.tsx
  • examples/example-vite-kitchen-sink/tailwind.config.ts
  • examples/example-vite-kitchen-sink/tsconfig.json
  • examples/example-vite-kitchen-sink/vite.config.ts
🧰 Additional context used
🪛 LanguageTool
examples/example-vite-kitchen-sink/README.md

[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)


[uncategorized] ~48-~48: You might be missing the article “the” here.
Context: ... ### Notes - you main want to updateactionscontract address insrc/compon...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

🪛 Biome
examples/example-vite-kitchen-sink/src/dojo/provider.tsx

[error] 13-14: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

examples/example-vite-kitchen-sink/src/lib/utils.ts

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

🔇 Additional comments (12)
examples/example-vite-kitchen-sink/src/dojo/provider.tsx (6)

1-5: LGTM: Imports are well-organized and comprehensive.

The imports cover all necessary dependencies for the provider implementation, including the Dojo SDK types, React hooks, and environment configurations.


7-9: LGTM: Well-implemented custom hook.

The useDojoDb hook provides a clean and convenient way to access the Dojo context in other components.


11-11: LGTM: Context creation is correct and well-typed.

The DojoContext is properly created with a null initial value and correctly typed with SDK<OnchainDashSchemaType>.


13-14: Replace empty interface with type alias.

As mentioned in a previous review, the DojoProviderProps interface is empty and doesn't provide any value. It's better to use a type alias in this case.

Replace the empty interface with a type alias:

-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-interface DojoProviderProps {
-}
+type DojoProviderProps = Record<string, never>;

This change addresses the static analysis warning and improves code clarity.

🧰 Tools
🪛 Biome

[error] 13-14: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


16-46: Enhance error handling in SDK initialization.

As suggested in a previous review, the error handling in the SDK initialization could be improved. Currently, errors are only logged to the console, which may not provide sufficient feedback to users or developers.

Consider implementing a more robust error handling mechanism:

  1. Create an error state to capture initialization errors.
  2. Display an error message to the user if initialization fails.
  3. Optionally, implement a retry mechanism.

Here's the suggested implementation:

 export default function DojoProvider({ children }: React.PropsWithChildren<DojoProviderProps>) {
   const [db, setDb] = useState<SDK<OnchainDashSchemaType> | null>(null);
+  const [error, setError] = useState<Error | null>(null);
+
+  const initializeSDK = () => {
+    import("@dojoengine/sdk").then(({ init }) => {
+      init<OnchainDashSchemaType>(
+        {
+          client: {
+            rpcUrl: getRpcUrl(),
+            toriiUrl: env.VITE_TORII_URL,
+            relayUrl: "",
+            worldAddress: dojoConfig.manifest.world.address,
+          },
+          domain: {
+            name: "OnChainDash",
+            revision: "1",
+          },
+        },
+        schema
+      ).then(setDb).catch(setError);
+    });
+  };
+
   useEffect(() => {
-    if (db === null && undefined !== window) {
-      import("@dojoengine/sdk").then(({ init }) => {
-        init<OnchainDashSchemaType>(
-          {
-            client: {
-              rpcUrl: getRpcUrl(),
-              toriiUrl: env.VITE_TORII_URL,
-              relayUrl: "",
-              worldAddress: dojoConfig.manifest.world.address,
-            },
-            domain: {
-              name: "OnChainDash",
-              revision: "1",
-            },
-          },
-          schema
-        ).then(setDb).catch(console.error);
-      });
+    if (db === null && error === null && typeof window !== 'undefined') {
+      initializeSDK();
     }
-  }, [db, setDb])
+  }, [db, error]);
+
+  if (error) {
+    return <div>Error initializing Dojo SDK: {error.message}</div>;
+  }

   return (
     <DojoContext.Provider value={db}>
       {children}
     </DojoContext.Provider >
   )
 }

This implementation provides better error handling and user feedback in case of initialization failures.


1-46: Summary: Well-structured Dojo provider with minor improvements needed.

Overall, the implementation of the Dojo provider is well-structured and provides the necessary functionality. However, there are two areas that need attention:

  1. Replace the empty DojoProviderProps interface with a type alias for better code clarity.
  2. Enhance the error handling in the SDK initialization process to provide better feedback and potentially implement a retry mechanism.

Addressing these points will improve the robustness and maintainability of the code.

🧰 Tools
🪛 Biome

[error] 13-14: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

examples/example-vite-kitchen-sink/src/lib/utils.ts (3)

4-6: LGTM: Efficient class name handling

The cn function effectively combines the power of clsx for conditional class names and twMerge for Tailwind CSS class merging. This is a solid approach for managing dynamic class names in React components using Tailwind CSS.


18-23: LGTM: Efficient character transliteration

The transliterate function is well-implemented, providing a flexible and efficient way to map characters based on a provided character map. Its use of array methods makes the code concise and readable.


65-68: LGTM: Effective ASCII normalization

The toValidAscii function effectively normalizes strings by removing accents and diacritical marks. The approach using NFD normalization followed by regex replacement and accentsToAscii is a robust method for achieving ASCII representation.

Note: The static analysis tool flagged a "misleading character class" on line 67, but this appears to be a false positive. The regex /[\u0300-\u036f]/g is correct for removing combining diacritical marks.

🧰 Tools
🪛 Biome

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

examples/example-vite-kitchen-sink/README.md (3)

1-3: LGTM: Clear and concise project introduction

The project title and description effectively communicate the purpose of the OnChainDash Vite Kitchen Sink example, showcasing dojo's capabilities beyond gaming.


5-34: LGTM: Comprehensive Getting Started guide

The Getting Started section provides clear and detailed instructions for setting up and running the project. It covers dependency installation, starting necessary services (katana and torii), and running the development server. The inclusion of options for both local development and mainnet/sepolia usage is particularly helpful.


36-44: LGTM: Clear instructions for local contract deployment

The Local Contracts Deployment section provides concise and accurate instructions for deploying contracts locally. It correctly mentions the prerequisite of having torii & katana running and includes the necessary commands for building and migrating contracts.

🧰 Tools
🪛 LanguageTool

[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)


### Notes

- you main want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix typo in the first note

There's a small typo in the first note.

Please apply the following change:

- - you main want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.
+ - you may want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.
📝 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
- you main want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.
- you may want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~48-~48: You might be missing the article “the” here.
Context: ... ### Notes - you main want to updateactionscontract address insrc/compon...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

Comment on lines 59 to 47
console.log("publish", res)
} catch (error) {
console.error("failed to publish message:", error);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling for better user experience.

The current error handling only logs errors to the console. Consider implementing user-friendly error messages or notifications to inform the user when message publishing fails.

Example implementation:

import { toast } from 'your-preferred-toast-library';

// In the publish function
try {
  const res = await db.client.publishMessage(JSON.stringify(msg), signature);
  console.log("publish", res);
  toast.success("Message published successfully!");
} catch (error) {
  console.error("failed to publish message:", error);
  toast.error("Failed to publish message. Please try again.");
}

Comment on lines 49 to 36
const publish = useCallback(async (data) => {
if (!account || !db) return;

const asciiMessage = toValidAscii(data.message);
const msg = generateTypedData(account?.address, asciiMessage)
try {
const signature = await account.signMessage(msg as TypedData);

try {
const res = await db.client.publishMessage(JSON.stringify(msg), signature);
console.log("publish", res)
} catch (error) {
console.error("failed to publish message:", error);
}

} catch (error) {
console.error("failed to sign message:", error);
}
// await db.client.publishMessage(JSON.stringify(msg), [signature.r, signature.s]);
// console.log("publish", data)
}, [db, account]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider extracting the publish function to a custom hook.

The publish function contains complex logic that could be reused in other components. Consider extracting it into a custom hook, e.g., usePublishMessage, to improve code organization and reusability.

Example implementation:

// In a new file, e.g., hooks/usePublishMessage.ts
export function usePublishMessage() {
  const { account } = useAccount();
  const db = useDojoDb();

  return useCallback(async (message: string) => {
    if (!account || !db) return;

    const asciiMessage = toValidAscii(message);
    const msg = generateTypedData(account?.address, asciiMessage);
    // ... rest of the publish logic
  }, [db, account]);
}

// In the Chat component
const publishMessage = usePublishMessage();
// Use publishMessage in handleSubmit

}, [db, account]);

return (
<form className="relative flex h-full min-h-[50vh] flex-col rounded-xl bg-muted/50 p-4 lg:col-span-2" onSubmit={handleSubmit((data) => publish(data))}>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Reset form after successful message publish.

The form doesn't reset after a successful message publish. Consider resetting the form to improve user experience.

Example implementation:

const { register, handleSubmit, reset } = useForm();

const onSubmit = useCallback(async (data) => {
  await publish(data);
  reset(); // Reset the form after successful publish
}, [publish, reset]);

return (
  <form onSubmit={handleSubmit(onSubmit)}>
    {/* ... rest of the form */}
  </form>
);

@MartianGreed MartianGreed force-pushed the feat/example-sink branch 2 times, most recently from 28a99b2 to b65118b Compare September 30, 2024 13:52
Copy link

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

🧹 Outside diff range and nitpick comments (8)
examples/example-vite-kitchen-sink/src/dojo/models.ts (5)

4-20: LGTM: Interfaces are well-structured. Consider adding documentation.

The GlobalCounter, CallerCounter, and Theme interfaces are well-defined and consistent. The use of fieldOrder in each interface is noteworthy and likely important for serialization or database operations.

Consider adding JSDoc comments to explain the purpose of each interface and their properties, especially the significance of fieldOrder and global_counter_key.


22-32: LGTM: Enum and constant are well-defined. Consider using string keys in AvailableThemeClassMap.

The AvailableTheme enum and AvailableThemeClassMap constant are well-defined and serve a clear purpose.

Consider using string keys in AvailableThemeClassMap for better maintainability:

export const AvailableThemeClassMap: Record<AvailableTheme, string> = {
  [AvailableTheme.Light]: 'light',
  [AvailableTheme.Dark]: 'dark',
  [AvailableTheme.Dojo]: 'dojo'
};

This approach is more robust against potential enum reordering and provides better type safety.


34-40: LGTM: OnchainDashSchemaType interface is well-structured. Consider adding documentation.

The OnchainDashSchemaType interface correctly extends SchemaType and incorporates the custom interfaces.

Consider adding a JSDoc comment to explain the purpose of this interface and its relationship to the on-chain dashboard concept.


42-62: LGTM: Schema initialization is correct. Consider improvements for clarity and maintainability.

The schema constant correctly initializes the GlobalCounter, CallerCounter, and Theme with default values consistent with their interfaces.

Consider the following improvements:

  1. Abstract magic numbers into named constants for better readability and maintainability:
    const DEFAULT_GLOBAL_COUNTER_KEY = 9999999;
    const DEFAULT_THEME_KEY = 9999999;
  2. Add comments explaining the significance of these default values, especially for global_counter_key and theme_key.
  3. Consider using a factory function to create the schema, which would allow for easier testing and potential runtime configuration:
    export function createSchema(options?: Partial<OnchainDashSchemaType>): OnchainDashSchemaType {
      return {
        onchain_dash: {
          GlobalCounter: {
            fieldOrder: ["counter", "global_counter_key"],
            counter: 0,
            global_counter_key: DEFAULT_GLOBAL_COUNTER_KEY,
          },
          // ... other initializations
        },
        ...options,
      };
    }
    
    export const schema = createSchema();

1-63: Overall, well-structured and type-safe implementation. Consider documentation and minor refactoring.

This file provides a comprehensive and well-organized schema for an on-chain dashboard with counters and theme management. The use of TypeScript features enhances type safety and clarity.

To further improve the file:

  1. Add comprehensive JSDoc comments to explain the purpose and usage of each interface, enum, and constant.
  2. Consider creating a separate types file if this schema is used across multiple components.
  3. Implement unit tests to ensure the schema behaves as expected, especially if you introduce factory functions as suggested earlier.
  4. If this schema is part of a larger system, consider documenting how it integrates with other components or modules in the project.
examples/example-vite-kitchen-sink/README.md (1)

38-38: Improve clarity of introductory sentence

The introductory sentence could be rephrased for better clarity.

Consider the following change:

- In order to make those commands work, you need to have torii & katana running.
+ Before running these commands, ensure that torii & katana are running.

This change makes the sentence more direct and easier to understand.

examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (2)

26-33: Component initialization and state setup look good, with a minor suggestion.

The component is well-structured with appropriate state management. However, consider initializing the useContractWrite hook with a more specific configuration if possible, rather than an empty calls array.

You might want to initialize the useContractWrite hook with a more specific configuration:

const { writeAsync } = useContractWrite({
  calls: [{ 
    contractAddress: dojoConfig.manifest.contracts[0].address,
    entrypoint: "change_theme"
  }]
});

This would make the intended use of the hook clearer from the start.


111-140: Render logic is well-implemented, with a minor accessibility suggestion.

The component's render logic is well-structured, using appropriate UI components and correctly mapping theme options to the handleChangeTheme function. The use of icons enhances the user experience.

Consider adding aria-label attributes to the theme selection buttons to improve accessibility. For example:

 <DropdownMenuItem onClick={() => handleChangeTheme(AvailableTheme.Light)}>
   Light
   <Sun className="h-4 w-4 ml-2" />
-  <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
+  <DropdownMenuShortcut aria-label="Shortcut: Shift Command P">⇧⌘P</DropdownMenuShortcut>
 </DropdownMenuItem>

Apply similar changes to the other theme options for consistent accessibility improvements.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between a8ca98a and b65118b.

⛔ Files ignored due to path filters (5)
  • examples/example-vite-kitchen-sink/public/dojo-logo.svg is excluded by !**/*.svg
  • examples/example-vite-kitchen-sink/src/app/favicon.ico is excluded by !**/*.ico
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistMonoVF.woff is excluded by !**/*.woff
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistVF.woff is excluded by !**/*.woff
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (40)
  • .gitmodules (1 hunks)
  • examples/example-vite-kitchen-sink/.env.dist (1 hunks)
  • examples/example-vite-kitchen-sink/.eslintrc.json (1 hunks)
  • examples/example-vite-kitchen-sink/.gitignore (1 hunks)
  • examples/example-vite-kitchen-sink/README.md (1 hunks)
  • examples/example-vite-kitchen-sink/components.json (1 hunks)
  • examples/example-vite-kitchen-sink/index.html (1 hunks)
  • examples/example-vite-kitchen-sink/package.json (1 hunks)
  • examples/example-vite-kitchen-sink/postcss.config.mjs (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/globals.css (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/layout.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/page.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/chat.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/header.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dropdown.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/models.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/env.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/lib/utils.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/main.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/tailwind.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/tsconfig.json (1 hunks)
  • examples/example-vite-kitchen-sink/vite.config.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (35)
  • .gitmodules
  • examples/example-vite-kitchen-sink/.env.dist
  • examples/example-vite-kitchen-sink/.eslintrc.json
  • examples/example-vite-kitchen-sink/.gitignore
  • examples/example-vite-kitchen-sink/components.json
  • examples/example-vite-kitchen-sink/index.html
  • examples/example-vite-kitchen-sink/package.json
  • examples/example-vite-kitchen-sink/postcss.config.mjs
  • examples/example-vite-kitchen-sink/src/app/globals.css
  • examples/example-vite-kitchen-sink/src/app/layout.tsx
  • examples/example-vite-kitchen-sink/src/app/page.tsx
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/chat.tsx
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/header.tsx
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx
  • examples/example-vite-kitchen-sink/src/dojo.config.ts
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx
  • examples/example-vite-kitchen-sink/src/env.ts
  • examples/example-vite-kitchen-sink/src/main.tsx
  • examples/example-vite-kitchen-sink/tailwind.config.ts
  • examples/example-vite-kitchen-sink/tsconfig.json
  • examples/example-vite-kitchen-sink/vite.config.ts
🧰 Additional context used
🪛 LanguageTool
examples/example-vite-kitchen-sink/README.md

[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)

🪛 Biome
examples/example-vite-kitchen-sink/src/lib/utils.ts

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

🔇 Additional comments (15)
examples/example-vite-kitchen-sink/src/dojo/models.ts (1)

1-1: LGTM: Import statement is appropriate.

The import of SchemaType from "@dojoengine/sdk" is correctly used in the file.

examples/example-vite-kitchen-sink/src/lib/utils.ts (3)

4-6: LGTM: Efficient class name combination

The cn function effectively combines class values using clsx and twMerge. This approach is a best practice for managing Tailwind CSS classes, ensuring proper merging and conflict resolution.


18-23: LGTM: Efficient character transliteration

The transliterate function is well-implemented and efficient. It uses a character map to replace characters in the input string, which is a good approach for transliteration tasks.


65-68: LGTM: Effective ASCII normalization

The toValidAscii function effectively normalizes strings by removing accents and diacritics. The approach of using normalize("NFD") followed by regex replacement and accentsToAscii is a robust method for achieving ASCII representation.

Note: The static analysis tool flagged a potential issue with the character class in the regex on line 67. However, this appears to be a false positive. The character class [\u0300-\u036f] is correctly used to match combining diacritical marks.

🧰 Tools
🪛 Biome

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

examples/example-vite-kitchen-sink/README.md (7)

1-3: LGTM: Clear and concise introduction

The title and introduction effectively introduce the OnChainDash Vite Kitchen Sink project and its purpose. This addresses the previous concern about properly introducing the dojo.js kitchen sink example.


5-34: LGTM: Comprehensive "Getting Started" section

The "Getting Started" section provides clear and detailed instructions for setting up and running the project. It includes steps for installing dependencies, starting necessary services (katana and torii), and running the development server. This effectively addresses the previous concern about providing relevant setup information for the dojo.js kitchen sink example.


36-44: LGTM: Clear instructions for local contract deployment

The "Local Contracts deployment" section provides concise and relevant instructions for deploying contracts locally. It correctly mentions the prerequisite of having torii & katana running.

🧰 Tools
🪛 LanguageTool

[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)


46-49: LGTM: Helpful additional notes

The "Notes" section provides useful additional information for users, including details about updating contract addresses and wallet compatibility.


48-48: Fix typo in the first note

As mentioned in a previous review comment, there's a typo in the first note.

Please apply the following change:

- - you main want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.
+ - you may want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.

1-49: Overall, good progress on the README with room for minor improvements

The README for the OnChainDash Vite Kitchen Sink project has been significantly improved. It now provides clear instructions for setting up and running the project, addressing many of the concerns raised in previous reviews. The content is relevant to the dojo.js kitchen sink example and provides valuable information for users.

Key points for improvement:

  1. Fix the typos mentioned in the review comments.
  2. Consider enhancing the clarity of some sentences, as suggested.
  3. Add the recommended additional sections to make the README more comprehensive.

Once these minor improvements are made, the README will be in excellent shape to serve as a guide for users of the dojo.js kitchen sink example.

🧰 Tools
🪛 LanguageTool

[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)


16-16: ⚠️ Potential issue

Fix typo in katana command

There's a small typo in the katana command. The --allowed-origins flag is missing a hyphen.

Please apply the following change:

- katana --disable-fee --allowed-origins "*"
+ katana --disable-fee --allowed-origins "*"

Likely invalid or redundant comment.

examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (3)

1-24: Imports and type definitions look good.

The imports are comprehensive and well-organized, covering all necessary dependencies for the component's functionality. The ThemeState interface is correctly defined.


35-43: handleChangeTheme function is well-implemented.

The function correctly uses useCallback for performance optimization and properly interacts with the smart contract to update the theme on-chain. The parsing of the theme to an integer is a good practice for ensuring correct data types in the contract call.


1-140: Overall, the ThemeSwitchButton component is well-implemented with room for optimization.

The component demonstrates good use of React hooks, proper interaction with the blockchain, and a well-structured UI. Key strengths include:

  1. Effective state management using useState and useEffect.
  2. Proper integration with on-chain data through custom hooks and SDK.
  3. A clean and intuitive user interface for theme switching.

Main areas for improvement:

  1. Optimize useEffect hooks by moving function definitions outside and refining dependency arrays.
  2. Enhance error handling throughout the component, especially in asynchronous operations.
  3. Improve performance by preventing unnecessary re-renders and DOM manipulations.
  4. Consider extracting some logic into custom hooks for better separation of concerns and reusability.
  5. Enhance accessibility in the rendered UI components.

Addressing these points will further improve the component's performance, maintainability, and user experience.

examples/example-vite-kitchen-sink/src/components/ui/dropdown.tsx (1)

1-205: Well-structured implementation of dropdown components

The dropdown components are thoughtfully implemented using React.forwardRef with appropriate TypeScript typings. Utilizing Radix UI primitives ensures accessibility and consistent behavior. The cn utility function effectively manages conditional class names, enhancing styling flexibility.

Comment on lines 45 to 62
const db = useDojoDb();
useEffect(() => {
async function getEntity(db: SDK<OnchainDashSchemaType>) {
const entity = await db.getEntities({
onchain_dash: {
Theme: { $: { where: { theme_key: { $eq: 9999999 } } } },
}
}, ({ data, error }) => { });
const counter = entity.pop();
if (!counter) {
return AvailableTheme.Light;
}
return AvailableTheme[counter.models.onchain_dash.Theme.value];
}
if (db) {
getEntity(db).then((th) => setTheme({ current: AvailableThemeClassMap[th], next: AvailableThemeClassMap[th] })).catch(console.error)
}
}, [address, db])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider optimizing the initial theme retrieval effect.

While the effect correctly retrieves the initial theme from the on-chain database, there are a few optimizations that could improve its performance and readability:

  1. Move the getEntity function outside the effect to prevent unnecessary re-creation on each render.
  2. Improve error handling by logging specific error messages.
  3. Consider using a custom hook for this logic to improve reusability and separation of concerns.

Here's a suggested refactor:

const getEntity = async (db: SDK<OnchainDashSchemaType>): Promise<AvailableTheme> => {
  try {
    const entity = await db.getEntities({
      onchain_dash: {
        Theme: { $: { where: { theme_key: { $eq: 9999999 } } } },
      }
    }, ({ data, error }) => { });
    const counter = entity.pop();
    return counter ? AvailableTheme[counter.models.onchain_dash.Theme.value] : AvailableTheme.Light;
  } catch (error) {
    console.error("Error fetching theme:", error);
    return AvailableTheme.Light;
  }
};

useEffect(() => {
  if (db) {
    getEntity(db)
      .then((th) => setTheme({ current: AvailableThemeClassMap[th], next: AvailableThemeClassMap[th] }))
      .catch(console.error);
  }
}, [db]);

This refactored version moves getEntity outside the effect, improves error handling, and simplifies the logic.

Comment on lines 64 to 98
useEffect(() => {
async function subscribeToEntityUpdates(db: SDK<OnchainDashSchemaType>) {
const sub = await db.subscribeEntityQuery({
onchain_dash: {
Theme: { $: { where: { theme_key: { $eq: 9999999 } } } }
}
}, ({ data, error }) => {
if (data) {
const entity = data.pop();
if (!entity) {
return AvailableTheme.Light;
}
if (entity.models.onchain_dash?.Theme?.value === undefined) {
return AvailableTheme.Light;
}

return AvailableTheme[entity.models.onchain_dash?.Theme?.value];
}
if (error) {
throw error;
}
});
setSub(sub);
}
if (address && db && sub === null) {
subscribeToEntityUpdates(db).then((th) => {
setTheme({ current: AvailableThemeClassMap[th], next: AvailableThemeClassMap[th] })
}).catch(console.error)
}
return () => {
if (sub) {
sub.free();
}
};
}, [address, db, sub, theme]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize the theme subscription effect.

The effect correctly sets up and cleans up the subscription to theme updates. However, there are several optimizations that could improve its performance and maintainability:

  1. Move the subscribeToEntityUpdates function outside the effect to prevent unnecessary re-creation.
  2. Improve error handling with more specific error messages.
  3. Remove 'theme' from the dependency array to prevent unnecessary re-subscriptions.
  4. Consider using a custom hook for this subscription logic.

Here's a suggested refactor:

const subscribeToEntityUpdates = async (db: SDK<OnchainDashSchemaType>, setTheme: React.Dispatch<React.SetStateAction<ThemeState>>) => {
  return await db.subscribeEntityQuery({
    onchain_dash: {
      Theme: { $: { where: { theme_key: { $eq: 9999999 } } } }
    }
  }, ({ data, error }) => {
    if (error) {
      console.error("Subscription error:", error);
      return;
    }
    if (data) {
      const entity = data.pop();
      const themeValue = entity?.models.onchain_dash?.Theme?.value;
      const newTheme = themeValue !== undefined ? AvailableTheme[themeValue] : AvailableTheme.Light;
      setTheme(prevTheme => ({ current: prevTheme.current, next: AvailableThemeClassMap[newTheme] }));
    }
  });
};

useEffect(() => {
  let subscription: Subscription | null = null;

  if (address && db && !sub) {
    subscribeToEntityUpdates(db, setTheme)
      .then(newSub => {
        subscription = newSub;
        setSub(newSub);
      })
      .catch(error => console.error("Failed to set up subscription:", error));
  }

  return () => {
    if (subscription) {
      subscription.free();
    }
  };
}, [address, db, sub]);

This refactored version improves error handling, removes unnecessary dependencies, and simplifies the logic.

Comment on lines 100 to 110
useEffect(() => {
if (null !== theme.current) {
document.body.classList.remove(theme.current);
}
if (null !== theme.next) {
document.body.classList.add(theme.next);
}


}, [theme]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize theme application effect.

The effect correctly applies theme changes to the document body, but there are a few improvements that could be made:

  1. Add a check to prevent unnecessary DOM manipulations when the current and next themes are the same.
  2. Ensure that theme classes exist before attempting to add or remove them.
  3. Consider using a more robust method for managing body classes to prevent potential conflicts with other components.

Here's a suggested refactor:

useEffect(() => {
  if (theme.current !== theme.next) {
    const validThemes = Object.values(AvailableThemeClassMap);
    document.body.classList.remove(...validThemes);
    if (theme.next && validThemes.includes(theme.next)) {
      document.body.classList.add(theme.next);
    }
  }
}, [theme.current, theme.next]);

This refactored version prevents unnecessary DOM manipulations, ensures that only valid theme classes are added or removed, and is more robust against potential conflicts with other components that might manipulate body classes.

Comment on lines +176 to +187
const DropdownMenuShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
)
}
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider memoizing DropdownMenuShortcut for performance optimization

While DropdownMenuShortcut is a simple component, wrapping it with React.memo can prevent unnecessary re-renders when its props remain unchanged, potentially improving performance in larger applications.

Apply this change to memoize the component:

 const DropdownMenuShortcut = React.memo(
   ({
     className,
     ...props
   }: React.HTMLAttributes<HTMLSpanElement>) => {
     return (
       <span
         className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
         {...props}
       />
     )
   }
 )
 DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
📝 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 DropdownMenuShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
)
}
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
const DropdownMenuShortcut = React.memo(
({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
)
}
)
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"

Copy link

@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: 4

🧹 Outside diff range and nitpick comments (2)
examples/example-vite-kitchen-sink/README.md (2)

5-34: LGTM: Comprehensive setup instructions with a minor typo

The "Getting Started" section provides clear and detailed instructions for setting up the project, including dependency installation, starting katana and torii server, and running the development server. It also covers both local development and potential use of sepolia/mainnet contracts.

There's a minor typo in line 13:

- https://rpc.netermind.io/(mainnet|sepolia)-juno
+ https://rpc.nethermind.io/(mainnet|sepolia)-juno

36-44: LGTM: Clear instructions for local contract deployment

The "Local Contracts deployment" section provides concise instructions for deploying contracts locally, including the prerequisite of having torii & katana running.

Consider simplifying the introductory sentence for better readability:

- In order to make those commands work, you need to have torii & katana running.
+ To run these commands, ensure torii & katana are running.
🧰 Tools
🪛 LanguageTool

[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between b65118b and 96337c9.

⛔ Files ignored due to path filters (5)
  • examples/example-vite-kitchen-sink/public/dojo-logo.svg is excluded by !**/*.svg
  • examples/example-vite-kitchen-sink/src/app/favicon.ico is excluded by !**/*.ico
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistMonoVF.woff is excluded by !**/*.woff
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistVF.woff is excluded by !**/*.woff
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (40)
  • .gitmodules (1 hunks)
  • examples/example-vite-kitchen-sink/.env.dist (1 hunks)
  • examples/example-vite-kitchen-sink/.eslintrc.json (1 hunks)
  • examples/example-vite-kitchen-sink/.gitignore (1 hunks)
  • examples/example-vite-kitchen-sink/README.md (1 hunks)
  • examples/example-vite-kitchen-sink/components.json (1 hunks)
  • examples/example-vite-kitchen-sink/index.html (1 hunks)
  • examples/example-vite-kitchen-sink/package.json (1 hunks)
  • examples/example-vite-kitchen-sink/postcss.config.mjs (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/globals.css (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/layout.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/page.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/chat.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/header.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dropdown.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/models.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/env.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/lib/utils.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/main.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/tailwind.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/tsconfig.json (1 hunks)
  • examples/example-vite-kitchen-sink/vite.config.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (38)
  • .gitmodules
  • examples/example-vite-kitchen-sink/.env.dist
  • examples/example-vite-kitchen-sink/.eslintrc.json
  • examples/example-vite-kitchen-sink/.gitignore
  • examples/example-vite-kitchen-sink/components.json
  • examples/example-vite-kitchen-sink/index.html
  • examples/example-vite-kitchen-sink/package.json
  • examples/example-vite-kitchen-sink/postcss.config.mjs
  • examples/example-vite-kitchen-sink/src/app/globals.css
  • examples/example-vite-kitchen-sink/src/app/layout.tsx
  • examples/example-vite-kitchen-sink/src/app/page.tsx
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/chat.tsx
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/header.tsx
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/dropdown.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx
  • examples/example-vite-kitchen-sink/src/dojo.config.ts
  • examples/example-vite-kitchen-sink/src/dojo/models.ts
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx
  • examples/example-vite-kitchen-sink/src/env.ts
  • examples/example-vite-kitchen-sink/src/main.tsx
  • examples/example-vite-kitchen-sink/tailwind.config.ts
  • examples/example-vite-kitchen-sink/tsconfig.json
  • examples/example-vite-kitchen-sink/vite.config.ts
🧰 Additional context used
🪛 LanguageTool
examples/example-vite-kitchen-sink/README.md

[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)

🪛 Biome
examples/example-vite-kitchen-sink/src/lib/utils.ts

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

🔇 Additional comments (4)
examples/example-vite-kitchen-sink/src/lib/utils.ts (3)

4-6: LGTM: Efficient class name handling

The cn function effectively combines the power of clsx for conditional class names and twMerge for Tailwind CSS class merging. This is a solid approach for managing dynamic class names in React components using Tailwind CSS.


18-23: LGTM: Efficient character transliteration

The transliterate function is well-implemented. It efficiently maps characters based on the provided character map, falling back to the original character if no mapping is found. This approach is both flexible and performant.


65-68: LGTM: Comprehensive ASCII normalization

The toValidAscii function provides a thorough approach to normalizing strings by removing accents and diacritics. The combination of NFD normalization, regex-based diacritic removal, and the accentsToAscii function ensures a comprehensive conversion to valid ASCII.

Note: The static analysis tool flagged a potential issue with the character class in the regular expression on line 67. However, this appears to be a false positive. The character class [\u0300-\u036f] is correctly used to match combining diacritical marks and is a standard approach for this task.

🧰 Tools
🪛 Biome

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

examples/example-vite-kitchen-sink/README.md (1)

1-3: LGTM: Clear and concise introduction

The introduction effectively sets the context for the OnChainDash Vite Kitchen Sink project, highlighting its purpose of showcasing dojo's capabilities beyond gaming.

Comment on lines 25 to 63
function accentsToAscii(str: string): string {
// Character map for transliteration to ASCII
const charMap: Record<string, string> = {
á: "a",
ú: "u",
é: "e",
ä: "a",
Š: "S",
Ï: "I",
š: "s",
Í: "I",
í: "i",
ó: "o",
ï: "i",
ë: "e",
ê: "e",
â: "a",
Ó: "O",
ü: "u",
Á: "A",
Ü: "U",
ô: "o",
ž: "z",
Ê: "E",
ö: "o",
č: "c",
Â: "A",
Ä: "A",
Ë: "E",
É: "E",
Č: "C",
Ž: "Z",
Ö: "O",
Ú: "U",
Ô: "O",
"‘": "'",
};
return transliterate(str, charMap);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize accentsToAscii for performance

As suggested in a previous review, consider optimizing the accentsToAscii function for better performance. The main improvement would be to move the charMap outside of the function to prevent it from being recreated on each function call.

Here's a suggested optimization:

const accentCharMap: Record<string, string> = {
  á: "a",
  ú: "u",
  // ... (rest of the map)
  "'": "'",
};

function accentsToAscii(str: string): string {
  return transliterate(str, accentCharMap);
}

This change will improve performance, especially if accentsToAscii is called frequently in your application.

Copy link

@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: 10

🧹 Outside diff range and nitpick comments (22)
examples/example-vite-kitchen-sink/src/components/ui/badge.tsx (1)

6-24: LGTM: Well-structured badge variants with a minor suggestion.

The badgeVariants definition using cva is well-structured and provides a good range of styling options. The use of variants for different badge types (default, secondary, destructive, and outline) allows for flexible and maintainable styling.

Consider adding an explicit type definition for the variant prop for improved clarity:

type BadgeVariant = 'default' | 'secondary' | 'destructive' | 'outline';

const badgeVariants = cva(
  // ... (existing code)
  {
    variants: {
      variant: {
        default: // ... (existing code),
        secondary: // ... (existing code),
        destructive: // ... (existing code),
        outline: // ... (existing code),
      } as Record<BadgeVariant, string>,
    },
    // ... (existing code)
  }
)

This addition would make the available variant options more explicit in the type system.

examples/example-vite-kitchen-sink/src/lib/utils.ts (2)

24-58: LGTM: Comprehensive character mapping

The charMap constant is well-defined:

  • It covers a wide range of accented characters and their ASCII equivalents.
  • Defining it as a constant outside of functions is good for performance, as it won't be recreated on each function call.

Consider adding a comment explaining the purpose of this map and possibly grouping similar characters together for better readability. For example:

// Map of accented characters to their ASCII equivalents
const charMap: Record<string, string> = {
  // Lowercase vowels
  á: "a", à: "a", â: "a", ä: "a",
  é: "e", è: "e", ê: "e", ë: "e",
  // ... (rest of the groupings)
};

70-72: LGTM: Efficient address shortening function

The shortAddress function is well-implemented:

  • It correctly truncates the address to show the first 6 and last 4 characters, which is a common pattern for displaying blockchain addresses.
  • The implementation is concise and efficient.

For improved robustness, consider adding a check for the minimum length of the address:

export function shortAddress(address: string): string {
  if (address.length < 11) return address; // or throw an error
  return `${address.slice(0, 6)}...${address.slice(-4)}`;
}

This ensures that the function works correctly even with very short inputs.

examples/example-vite-kitchen-sink/README.md (2)

1-3: Minor grammatical improvement suggested

The introduction effectively communicates the purpose of the project. Consider this minor grammatical improvement:

- This project aims at showcasing dojo's capabilities outside of gaming.
+ This project aims to showcase dojo's capabilities outside of gaming.

This change makes the sentence flow more naturally.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~3-~3: You might be missing the article “the” here.
Context: ...n Sink This project aims at showcasing dojo's capabilities outside of gaming. ## G...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


37-38: Improve wording for clarity

Consider rephrasing the sentence for better clarity:

- In order to make those commands work, you need to have torii & katana running.
+ To execute these commands successfully, ensure that torii & katana are running.

This change makes the instruction more direct and easier to understand.

🧰 Tools
🪛 LanguageTool

[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)

examples/example-vite-kitchen-sink/src/components/ui/button.tsx (5)

1-5: LGTM! Consider using named import for React.

The imports look good and are appropriate for the component. However, for better tree-shaking, consider using named imports from React instead of the namespace import.

You can update the React import like this:

-import * as React from "react"
+import { forwardRef } from "react"

This change would require updating the React.forwardRef usage later in the file to just forwardRef.


7-34: LGTM! Consider consistent formatting for multi-line strings.

The button variants are well-defined and cover a good range of use cases. The use of cva provides flexibility and maintainability.

For consistency, consider formatting all multi-line strings in the same way. For example:

 const buttonVariants = cva(
-  "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
+  [
+    "inline-flex items-center justify-center whitespace-nowrap rounded-md",
+    "text-sm font-medium ring-offset-background transition-colors",
+    "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
+    "disabled:pointer-events-none disabled:opacity-50",
+  ].join(" "),
   {
     variants: {
       variant: {
         default: "bg-primary text-primary-foreground hover:bg-primary/90",
-        destructive:
-          "bg-destructive text-destructive-foreground hover:bg-destructive/90",
+        destructive: [
+          "bg-destructive text-destructive-foreground",
+          "hover:bg-destructive/90",
+        ].join(" "),
         // ... (apply similar changes to other multi-line variants)
       },
       // ... (rest of the code remains unchanged)
     },
   }
 )

This approach improves readability and makes it easier to add or modify classes in the future.


36-40: LGTM! Consider adding JSDoc comments for better documentation.

The ButtonProps interface is well-defined, extending the necessary types and including the 'asChild' prop for polymorphic usage.

To improve documentation, consider adding JSDoc comments to explain the purpose of the interface and the 'asChild' prop:

/**
 * Props for the Button component.
 * Extends standard button HTML attributes and variant props.
 */
export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  /**
   * If true, the component will render its children directly instead of wrapping them in a button element.
   * This is useful for creating composite components that behave like buttons.
   */
  asChild?: boolean
}

This addition would make the code more self-documenting and easier for other developers to understand and use.


42-54: LGTM! Consider using more specific types for destructured props.

The Button component is well-implemented, using forwardRef and handling the 'asChild' prop correctly for polymorphic usage.

To improve type safety, consider explicitly typing the destructured props:

 const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
-  ({ className, variant, size, asChild = false, ...props }, ref) => {
+  ({ className, variant, size, asChild = false, ...props }: ButtonProps, ref: React.ForwardedRef<HTMLButtonElement>) => {
     const Comp = asChild ? Slot : "button"
     return (
       <Comp
         className={cn(buttonVariants({ variant, size, className }))}
         ref={ref}
         {...props}
       />
     )
   }
 )

This change makes the types more explicit and can help catch potential type-related issues earlier in development.


1-56: Great work on the Button component! Consider adding tests.

The Button component is well-implemented, using modern React patterns and providing a high degree of flexibility through variants and polymorphic usage. It's a solid foundation for a UI library or design system.

To ensure the component's reliability and make it easier to maintain and refactor in the future, consider adding a test file for this component.

Would you like assistance in creating a test file for this Button component? I can help generate some basic test cases using a testing library like Jest and React Testing Library.

examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (1)

35-54: LGTM: DrawerContent component is well-implemented, but consider accessibility.

The DrawerContent component is correctly implemented as a forwardRef component. It properly includes the DrawerOverlay and adds a loading indicator. The styling is appropriate for a bottom drawer.

Consider adding an aria-label to the loading indicator div for better accessibility:

-      <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
+      <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" aria-label="Loading indicator" />
examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (1)

100-129: LGTM: Well-structured render logic with a minor suggestion.

The render logic is clean, well-structured, and makes good use of the design system components. The onClick handlers for theme selection are correctly implemented.

Consider extracting the theme options into a separate constant or configuration object. This would make it easier to add or modify themes in the future:

const THEME_OPTIONS = [
  { value: AvailableTheme.Light, label: 'Light', icon: Sun, shortcut: '⇧⌘P' },
  { value: AvailableTheme.Dark, label: 'Dark', icon: Moon, shortcut: '⌘B' },
  { value: AvailableTheme.Dojo, label: 'Dojo', shortcut: '⌘S' },
];

// Then in the render:
{THEME_OPTIONS.map(({ value, label, icon: Icon, shortcut }) => (
  <DropdownMenuItem key={value} onClick={() => handleChangeTheme(value)}>
    {label}
    {Icon && <Icon className="h-4 w-4 ml-2" />}
    <DropdownMenuShortcut>{shortcut}</DropdownMenuShortcut>
  </DropdownMenuItem>
))}

This approach would make the component more maintainable and easier to extend in the future.

examples/example-vite-kitchen-sink/src/components/chat.tsx (3)

22-29: LGTM: Component initialization is well-structured.

The Chat component is properly initialized with the necessary hooks for form management, account handling, and state management.

Consider adding a brief comment explaining the purpose of the useDojoDb hook for better code documentation.


62-84: LGTM: Real-time update subscription is well-implemented.

The useEffect hook for subscribing to real-time updates is properly structured and handles potential undefined cases correctly.

Consider using the functional update form of setMessages to ensure you're always working with the latest state:

setMessages(prevMessages => [...prevMessages, msg]);

This approach is more reliable in scenarios where multiple state updates might occur in quick succession.


99-136: LGTM: Component render logic is well-structured.

The render logic for the Chat component is well-implemented, using appropriate UI components and correctly displaying the message list with sender information.

Consider adding an aria-label to the form element to improve accessibility:

- <form ref={formRef} className="relative flex h-full min-h-[50vh] flex-col rounded-xl bg-muted/50 p-4 lg:col-span-2" onSubmit={handleSubmit((data) => publish(data))} onKeyPress={handleKeyPress}>
+ <form ref={formRef} className="relative flex h-full min-h-[50vh] flex-col rounded-xl bg-muted/50 p-4 lg:col-span-2" onSubmit={handleSubmit((data) => publish(data))} onKeyPress={handleKeyPress} aria-label="Chat message form">

This will provide better context for screen reader users.

examples/example-vite-kitchen-sink/src/components/ui/select.tsx (3)

13-31: LGTM: Well-implemented SelectTrigger component with a minor suggestion.

The SelectTrigger component is well-implemented using React.forwardRef and the cn utility for class name composition. The styling covers various states and the use of the ChevronDown icon provides a clear visual indicator.

Consider adding an aria-haspopup="listbox" attribute to enhance accessibility:

 <SelectPrimitive.Trigger
   ref={ref}
+  aria-haspopup="listbox"
   className={cn(
     // ... (existing classes)
   )}
   {...props}
 >

This addition will explicitly indicate that the trigger opens a listbox, improving screen reader support.


68-98: LGTM: Comprehensive SelectContent component with a suggestion for optimization.

The SelectContent component is well-implemented, using React.forwardRef and Radix UI's Portal for proper DOM positioning. The conditional styling based on the position prop provides flexibility for various use cases.

Consider memoizing the className computation to optimize performance, especially if this component is rendered frequently:

const getContentClassName = React.useMemo(() => {
  return cn(
    "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
    position === "popper" &&
    "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
    className
  )
}, [position, className]);

// Then use getContentClassName in the component

This optimization can help reduce unnecessary re-computations of the className string.


112-133: LGTM: Well-implemented SelectItem component with a suggestion for accessibility.

The SelectItem component is well-implemented, providing clear visual feedback for different states (focus, disabled, selected). The use of SelectPrimitive.ItemIndicator with a check icon effectively shows selected items.

To enhance accessibility, consider adding an aria-selected attribute:

 <SelectPrimitive.Item
   ref={ref}
+  aria-selected={props.selected}
   className={cn(
     // ... (existing classes)
   )}
   {...props}
 >

This addition will explicitly indicate the selected state to screen readers, improving the overall accessibility of the component.

examples/example-vite-kitchen-sink/src/components/header.tsx (2)

34-35: LGTM: Header structure and logo

The header structure is well-designed with appropriate use of flexbox and semantic HTML. The logo includes alt text, which is good for accessibility.

Consider using CSS variables for the logo size to make it easier to adjust across the application:

- <img src="/dojo-logo.svg" alt="Dojo logo" className="h-24 w-24" />
+ <img src="/dojo-logo.svg" alt="Dojo logo" className="h-[var(--logo-size)] w-[var(--logo-size)]" />

Then define --logo-size: 6rem; (or your preferred size) in your global CSS.


155-166: LGTM: Additional UI components with minor adjustment

The additional UI components (ThemeSwitchButton, WalletAccount, and Share button) are well-integrated into the header.

Update the Share icon size to use the size prop:

- <Share className="size-3.5" />
+ <Share size={14} />

This change ensures consistent usage of the icon component properties.

examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (1)

45-48: Ensure Close Button is Accessible

The close button lacks an explicit aria-label, which can improve accessibility for assistive technologies. Consider adding an aria-label to the DialogPrimitive.Close component.

Apply the following change:

<DialogPrimitive.Close
  className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
+ aria-label="Close"
>
examples/example-vite-kitchen-sink/src/components/ui/dropdown.tsx (1)

25-205: Consider Adding JSDoc Comments for Better Documentation

Adding JSDoc comments to each component can improve code readability and assist other developers in understanding the purpose and usage of each component.

For example, you could add:

+/**
+ * DropdownMenuSubTrigger component triggers a submenu within the dropdown.
+ * @param inset - Optional boolean to adjust the padding.
+ */
 const DropdownMenuSubTrigger = React.forwardRef<
   React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
   React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
     inset?: boolean
   }
 >(({ className, inset, children, ...props }, ref) => (
   // component implementation
 ))
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 96337c9 and 4104f89.

⛔ Files ignored due to path filters (5)
  • examples/example-vite-kitchen-sink/public/dojo-logo.svg is excluded by !**/*.svg
  • examples/example-vite-kitchen-sink/src/app/favicon.ico is excluded by !**/*.ico
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistMonoVF.woff is excluded by !**/*.woff
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistVF.woff is excluded by !**/*.woff
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (41)
  • .gitmodules (1 hunks)
  • examples/example-vite-kitchen-sink/.env.dist (1 hunks)
  • examples/example-vite-kitchen-sink/.eslintrc.json (1 hunks)
  • examples/example-vite-kitchen-sink/.gitignore (1 hunks)
  • examples/example-vite-kitchen-sink/README.md (1 hunks)
  • examples/example-vite-kitchen-sink/components.json (1 hunks)
  • examples/example-vite-kitchen-sink/index.html (1 hunks)
  • examples/example-vite-kitchen-sink/package.json (1 hunks)
  • examples/example-vite-kitchen-sink/postcss.config.mjs (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/globals.css (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/layout.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/page.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/chat.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/header.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dropdown.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/models.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/env.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/lib/utils.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/main.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/tailwind.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/tsconfig.json (1 hunks)
  • examples/example-vite-kitchen-sink/vite.config.ts (1 hunks)
  • worlds/onchain-dash (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • worlds/onchain-dash
🚧 Files skipped from review as they are similar to previous changes (28)
  • .gitmodules
  • examples/example-vite-kitchen-sink/.env.dist
  • examples/example-vite-kitchen-sink/.eslintrc.json
  • examples/example-vite-kitchen-sink/.gitignore
  • examples/example-vite-kitchen-sink/components.json
  • examples/example-vite-kitchen-sink/index.html
  • examples/example-vite-kitchen-sink/package.json
  • examples/example-vite-kitchen-sink/postcss.config.mjs
  • examples/example-vite-kitchen-sink/src/app/globals.css
  • examples/example-vite-kitchen-sink/src/app/layout.tsx
  • examples/example-vite-kitchen-sink/src/app/page.tsx
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx
  • examples/example-vite-kitchen-sink/src/dojo.config.ts
  • examples/example-vite-kitchen-sink/src/dojo/models.ts
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx
  • examples/example-vite-kitchen-sink/src/env.ts
  • examples/example-vite-kitchen-sink/src/main.tsx
  • examples/example-vite-kitchen-sink/tailwind.config.ts
  • examples/example-vite-kitchen-sink/tsconfig.json
  • examples/example-vite-kitchen-sink/vite.config.ts
🧰 Additional context used
🪛 LanguageTool
examples/example-vite-kitchen-sink/README.md

[uncategorized] ~3-~3: You might be missing the article “the” here.
Context: ...n Sink This project aims at showcasing dojo's capabilities outside of gaming. ## G...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)


[uncategorized] ~48-~48: You might be missing the article “the” here.
Context: ... ### Notes - you main want to updateactionscontract address insrc/compon...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

🪛 Biome
examples/example-vite-kitchen-sink/src/lib/utils.ts

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

🔇 Additional comments (40)
examples/example-vite-kitchen-sink/src/components/ui/badge.tsx (4)

1-4: LGTM: Imports are appropriate and well-organized.

The imports cover all necessary dependencies for the component, including React, class-variance-authority for styling, and a local utility function. This setup suggests good code organization and maintainable styling practices.


36-36: LGTM: Appropriate exports.

Exporting both the Badge component and badgeVariants function is a good practice. It provides flexibility for users of this module, allowing them to use the pre-defined styles in other contexts if needed.


30-34: 🛠️ Refactor suggestion

Consider refining prop handling for improved type safety.

I agree with the previous review comment regarding type safety for prop spreading. While spreading props allows for flexibility, it can potentially lead to passing inappropriate props to the DOM.

Here's an alternative approach that maintains flexibility while improving type safety:

import * as React from "react"

function Badge({ 
  className, 
  variant, 
  children,
  ...props
}: BadgeProps & { children: React.ReactNode }) {
  return (
    <div 
      className={cn(badgeVariants({ variant }), className)}
      {...props}
    >
      {children}
    </div>
  )
}

This approach explicitly handles the children prop, which is a common use case for a Badge component, while still allowing other HTML attributes to be passed through.


1-36: Overall assessment: Good addition with minor improvement suggestions.

This Badge component is a valuable addition to the kitchen sink example for the dojo.js project. It demonstrates the use of class-variance-authority for flexible and maintainable styling, which could be beneficial for users of the project.

Regarding the PR objectives:

  1. The component adds to the kitchen sink example as intended.
  2. Documentation could be improved by adding JSDoc comments to the Badge component and badgeVariants function.
  3. Tests should be added to ensure the component behaves as expected.
  4. A CI job for the new examples should be created as mentioned in the PR checklist.

To help with the PR objectives, here's a script to check for the presence of tests and documentation:

Please ensure these items are addressed before merging the PR.

examples/example-vite-kitchen-sink/src/lib/utils.ts (5)

4-6: LGTM: Efficient class name utility function

The cn function is well-implemented, using clsx for combining class values and twMerge for intelligent merging of Tailwind CSS classes. This approach is a best practice for handling dynamic class names in React components with Tailwind.


18-23: LGTM: Efficient transliteration function

The transliterate function is well-implemented:

  • It uses a functional approach with split, map, and join for efficient character mapping.
  • The default empty object for charMap is a good practice, allowing the function to be called without a map if needed.
  • The implementation is concise and easy to understand.

60-63: LGTM: Efficient accent removal function

The accentsToAscii function is well-implemented:

  • It efficiently uses the transliterate function with the predefined charMap.
  • The charMap is correctly defined outside the function, addressing the performance concern raised in the previous review.

65-68: LGTM: Comprehensive ASCII conversion function

The toValidAscii function is well-implemented:

  • It uses string normalization (NFD) to separate base characters and combining marks.
  • The regex [\u0300-\u036f] correctly targets and removes diacritical marks.
  • It applies accentsToAscii for further transliteration of any remaining accented characters.

Note: The static analysis tool flagged a "misleading character class" on line 67, but this is a false positive. The character class [\u0300-\u036f] is correct for removing diacritical marks in the Unicode range for combining diacritical marks.

🧰 Tools
🪛 Biome

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)


8-16: ⚠️ Potential issue

Improve ensureStarkFelt implementation

The current implementation of ensureStarkFelt still has some potential issues:

  1. There's no validation to ensure the input is a valid hexadecimal string.
  2. Inputs longer than 66 characters are not handled explicitly.
  3. The behavior for inputs not starting with "0x" might be unexpected.

Consider implementing the following improvements:

export function ensureStarkFelt(value: string): string {
  const hexRegex = /^(0x)?[0-9A-Fa-f]+$/;
  
  if (!hexRegex.test(value)) {
    throw new Error("Invalid input: not a hexadecimal string");
  }

  if (!value.startsWith("0x")) {
    value = "0x" + value;
  }

  const hexPart = value.slice(2);
  if (hexPart.length > 64) {
    throw new Error("Input exceeds maximum length for a Stark felt");
  }

  return "0x" + hexPart.padStart(64, "0");
}

This implementation addresses the issues by:

  1. Validating that the input is a valid hexadecimal string.
  2. Always adding the "0x" prefix.
  3. Ensuring the result is always 66 characters long (including "0x").
  4. Rejecting inputs that would result in a value longer than 66 characters.

Please review and adjust based on the specific requirements of Stark felt in your project.

examples/example-vite-kitchen-sink/README.md (2)

48-48: Fix typo in the first note

As mentioned in a previous review, there's a typo in the first note. Please apply the following correction:

- - you main want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.
+ - you may want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.

This change ensures the note is clear and grammatically correct.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~48-~48: You might be missing the article “the” here.
Context: ... ### Notes - you main want to updateactionscontract address insrc/compon...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


1-49: Enhance README with additional sections

As suggested in a previous review, consider enhancing the README with the following additional sections to make it more comprehensive:

  1. Features Demonstrated

    • List the key dojo.js features showcased in this kitchen sink example.
  2. Example Structure

    • Provide an overview of how the example is organized.
    • Explain how to navigate through different parts of the example.
  3. Learn More

    • Include links to dojo.js documentation and other relevant resources.
  4. Contributing

    • Add information on how to contribute to improving this example.
  5. License

    • Include license information for the example code.

These additions would significantly enhance the README, making it more informative and user-friendly.

Would you like assistance in drafting content for these sections?

🧰 Tools
🪛 LanguageTool

[uncategorized] ~3-~3: You might be missing the article “the” here.
Context: ...n Sink This project aims at showcasing dojo's capabilities outside of gaming. ## G...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)


[uncategorized] ~48-~48: You might be missing the article “the” here.
Context: ... ### Notes - you main want to updateactionscontract address insrc/compon...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

examples/example-vite-kitchen-sink/src/components/ui/button.tsx (1)

56-56: LGTM! Exports look good.

Exporting both the Button component and buttonVariants is a good practice. It allows users of this module to have flexibility in how they use the button styles.

examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (7)

1-4: LGTM: Imports are well-structured and appropriate.

The import statements are clear and concise. Renaming the Drawer import to DrawerPrimitive is a good practice to avoid naming conflicts with the custom Drawer component being created.


6-15: LGTM: Drawer component is well-implemented.

The Drawer component is a clean wrapper around DrawerPrimitive.Root. It properly handles the shouldScaleBackground prop and spreads other props correctly. The use of displayName is good for debugging purposes.


17-21: LGTM: DrawerTrigger, DrawerPortal, and DrawerClose are appropriately defined.

These components are correctly aliased from the DrawerPrimitive components. This approach provides flexibility for future customization if needed while maintaining a consistent API.


23-33: LGTM: DrawerOverlay component is well-implemented.

The DrawerOverlay component is correctly implemented as a forwardRef component. It properly applies styling using the cn utility and spreads additional props. The use of displayName is good for debugging purposes.


56-76: LGTM: DrawerHeader and DrawerFooter components are well-implemented.

Both DrawerHeader and DrawerFooter components are implemented correctly. They use the cn utility consistently for className composition and properly spread additional props. The use of displayName is good for debugging purposes.


78-103: LGTM: DrawerTitle and DrawerDescription components are well-implemented.

Both DrawerTitle and DrawerDescription components are correctly implemented as forwardRef components. They properly apply styling using the cn utility and spread additional props. The use of displayName is good for debugging purposes.


105-116: LGTM: Export statement is comprehensive.

The export statement includes all components defined in the file, allowing for easy import and use of these components in other parts of the application.

examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (3)

1-24: LGTM: Imports and type definitions are appropriate.

The imports cover all necessary dependencies for the component's functionality, including React hooks, UI components, and custom hooks. The ThemeState interface is well-defined and used consistently throughout the component.


36-44: Verify theme parsing in handleChangeTheme function.

The handleChangeTheme function parses the theme parameter as an integer using parseInt(theme, 10). Please verify that the AvailableTheme enum values are indeed numeric and that this parsing is necessary and correct.

#!/bin/bash
# Description: Check the definition of AvailableTheme enum to ensure it uses numeric values.
rg --type typescript 'enum\s+AvailableTheme' -A 10

31-33: Verify the empty calls array in useContractWrite.

The useContractWrite hook is initialized with an empty calls array. While this might be intentional, it's worth verifying if this is the desired behavior or if it should be populated with initial calls.

examples/example-vite-kitchen-sink/src/components/chat.tsx (5)

1-20: LGTM: Imports and type definitions are well-structured.

The imports cover all necessary dependencies for the component's functionality, and the MessageItem interface is properly defined with the required fields.


30-47: LGTM: Publish function is well-implemented with proper error handling.

The publish function is well-structured, handling message conversion, signing, and publishing. It also resets the form after successful publishing, which addresses a previous review comment.

As mentioned in a previous review, consider implementing user-friendly error messages or notifications to inform the user when message publishing fails, instead of just logging to the console.


49-60: LGTM: Initial message fetching is properly implemented.

The useEffect hook for fetching initial messages is well-structured. It correctly handles the case when there are no messages and ensures that messages are sorted chronologically before updating the state.


86-97: LGTM: Key press handling is well-implemented.

The handleKeyPress function correctly handles form submission on Enter key press while allowing multi-line input with Shift+Enter. The use of formRef for programmatic form submission is a good practice.


1-136: Overall, the Chat component is well-implemented and meets the PR objectives.

This new Chat component provides a comprehensive example of real-time messaging functionality using dojo.js. It demonstrates good practices in React development, including proper use of hooks, error handling, and real-time data subscription.

A few minor suggestions have been made to further improve the code:

  1. Adding a comment to explain the useDojoDb hook.
  2. Implementing user-friendly error messages for failed message publishing.
  3. Using the functional update form of setMessages for more reliable state updates.
  4. Adding an aria-label to the form element for improved accessibility.

These changes will enhance the component's robustness and user experience. Great job on implementing this kitchen sink example!

examples/example-vite-kitchen-sink/src/components/ui/select.tsx (6)

1-5: LGTM: Imports are appropriate and follow best practices.

The import statements are well-organized and import the necessary dependencies for creating accessible and customizable select components using Radix UI primitives. The use of the cn utility from a local utils file is a good practice for managing class names.


7-11: LGTM: Good use of Radix UI primitives.

The Select, SelectGroup, and SelectValue components are well-defined as aliases for Radix UI primitives. This approach provides flexibility for future customizations while maintaining a consistent naming convention throughout the application.


33-66: LGTM: Well-implemented scroll button components.

The SelectScrollUpButton and SelectScrollDownButton components are consistently implemented using React.forwardRef. The use of ChevronUp and ChevronDown icons provides clear visual indicators for scrolling directions. The components are styled appropriately and maintain consistency with the overall design.


100-110: LGTM: Well-implemented SelectLabel component.

The SelectLabel component is consistently implemented using React.forwardRef. The styling applied provides appropriate padding and font properties, ensuring a clear visual distinction for labels within the select dropdown.


135-145: LGTM: Well-implemented SelectSeparator component.

The SelectSeparator component is consistently implemented using React.forwardRef. The styling applied creates a clear visual separation between groups of items in the select dropdown, enhancing the overall user experience and organization of the options.


147-158: LGTM: Comprehensive export of all components.

The export statement includes all the components defined in the file, making them easily accessible for use in other parts of the application. This approach promotes modularity and reusability of the select components.

examples/example-vite-kitchen-sink/src/components/header.tsx (2)

1-31: LGTM: Imports and component declaration

The imports are well-organized and the Header component is correctly declared as a functional component.


1-169: Overall assessment: Well-implemented header component

The Header component is well-structured and aligns with the PR objective of adding a kitchen sink example to the dojo.js project. It includes:

  1. A logo and title for the "OnChain Dash" application
  2. A settings drawer with model configuration options
  3. Theme switching and wallet account integration
  4. A share button

The component demonstrates good use of various UI elements and responsive design. With the suggested accessibility and consistency improvements, this will serve as an excellent example for the project.

To ensure all necessary elements are present for a comprehensive kitchen sink example, please run the following script:

This script will help ensure that all key components and features expected in a comprehensive kitchen sink example are present in the implementation.

✅ Verification successful

Verification Successful: All key components and features are present

The kitchen sink example includes all essential UI components, theme switching functionality, wallet integration, and model configuration options as required.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the presence of key components and features in the kitchen sink example

# Test: Check for essential UI components
echo "Checking for essential UI components..."
rg --type typescript 'import.*from.*@/components/ui/' examples/example-vite-kitchen-sink/src

# Test: Verify the presence of theme switching functionality
echo "Verifying theme switching functionality..."
rg --type typescript 'import.*ThemeSwitchButton' examples/example-vite-kitchen-sink/src

# Test: Check for wallet integration
echo "Checking for wallet integration..."
rg --type typescript 'import.*WalletAccount' examples/example-vite-kitchen-sink/src

# Test: Verify the presence of model configuration options
echo "Verifying model configuration options..."
rg --type typescript 'temperature|top-p|top-k' examples/example-vite-kitchen-sink/src

echo "Kitchen sink example verification complete."

Length of output: 949


Script:

#!/bin/bash
# Description: Verify the presence of key components and features in the kitchen sink example with corrected file type usage

# Test: Check for essential UI components
echo "Checking for essential UI components..."
rg 'import.*from.*@/components/ui/' examples/example-vite-kitchen-sink/src --glob '*.ts' --glob '*.tsx'

# Test: Verify the presence of theme switching functionality
echo "Verifying theme switching functionality..."
rg 'import.*ThemeSwitchButton' examples/example-vite-kitchen-sink/src --glob '*.ts' --glob '*.tsx'

# Test: Check for wallet integration
echo "Checking for wallet integration..."
rg 'import.*WalletAccount' examples/example-vite-kitchen-sink/src --glob '*.ts' --glob '*.tsx'

# Test: Verify the presence of model configuration options
echo "Verifying model configuration options..."
rg 'temperature|top-p|top-k' examples/example-vite-kitchen-sink/src --glob '*.ts' --glob '*.tsx'

echo "Kitchen sink example verification complete."

Length of output: 2602

examples/example-vite-kitchen-sink/src/components/sidebar.tsx (3)

1-21: LGTM: Imports are appropriate and well-organized.

The imports cover all necessary icons, UI components, and hooks required for the sidebar functionality.


30-37: LGTM: Hooks and state management are well-implemented.

The use of useConnect and useState hooks is appropriate for managing the component's state and wallet connection functionality.


165-165: ⚠️ Potential issue

Fix inconsistent aria-label for the Account button

The aria-label for the Account button is incorrectly set to "Help". This should be updated to "Account" for proper accessibility.

Update the aria-label as follows:

-  aria-label="Help"
+  aria-label="Account"

Likely invalid or redundant comment.

examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (1)

1-120: Well-Structured and Accessible Dialog Components

The new dialog components are well-implemented, leveraging Radix UI primitives effectively. The use of React.forwardRef and proper displayName assignments enhances component traceability and reusability. Good work!

examples/example-vite-kitchen-sink/src/components/ui/dropdown.tsx (1)

1-205: Well-Structured Implementation of Dropdown Components

The dropdown menu components are well-defined, utilizing Radix UI primitives effectively. The use of React.forwardRef and TypeScript types enhances reusability and type safety. The code is clean and follows best practices.

Comment on lines +26 to +28
export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> { }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider expanding the BadgeProps interface for clarity.

While the current BadgeProps interface correctly combines HTML div attributes with the variant props, it could be more explicit about the available props.

Consider expanding the interface to explicitly list the props:

export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement> {
  variant?: VariantProps<typeof badgeVariants>['variant'];
  className?: string;
}

This approach makes the component's API more explicit and can improve developer experience when using the Badge component.

# with katana
torii --world 0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12 --allowed-origins "*"
# with mainnet|sepolia
torii --world 0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12 --allowed-origins "*" --rpc "https://rpc.nethermind.io/(mainnet|sepolia)-juno?apikey={apikey}" -s 204922
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix typo in RPC URL

There's a typo in the RPC URL for mainnet/sepolia. Please correct it as follows:

- torii --world 0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12 --allowed-origins "*" --rpc "https://rpc.nethermind.io/(mainnet|sepolia)-juno?apikey={apikey}" -s 204922 
+ torii --world 0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12 --allowed-origins "*" --rpc "https://rpc.nethermind.io/(mainnet|sepolia)-juno?apikey={apikey}" -s 204922 

This ensures that users can correctly access the RPC endpoint.

Committable suggestion was skipped due to low confidence.

Comment on lines +1 to +116
const DrawerTrigger = DrawerPrimitive.Trigger

const DrawerPortal = DrawerPrimitive.Portal

const DrawerClose = DrawerPrimitive.Close

const DrawerOverlay = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn("fixed inset-0 z-50 bg-black/80", className)}
{...props}
/>
))
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName

const DrawerContent = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
className
)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
))
DrawerContent.displayName = "DrawerContent"

const DrawerHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
{...props}
/>
)
DrawerHeader.displayName = "DrawerHeader"

const DrawerFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
)
DrawerFooter.displayName = "DrawerFooter"

const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DrawerTitle.displayName = DrawerPrimitive.Title.displayName

const DrawerDescription = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
DrawerDescription.displayName = DrawerPrimitive.Description.displayName

export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Missing Tests and Documentation for Drawer Components

The verification indicates that the following PR objectives are not fully met:

  1. Tests: No test files found for the Drawer components.
  2. Documentation: No documentation files found for the new Drawer components.
  3. CI Configuration: While existing CI workflows are present, there is no dedicated CI job for these new examples.

Please address these items to fully satisfy the PR requirements.

🔗 Analysis chain

Overall, excellent implementation of the Drawer components.

This file provides a comprehensive set of Drawer components that are well-implemented, consistent, and follow React best practices. The use of the vaul library and the cn utility function is consistent throughout, and the components provide a flexible API for implementing drawer functionality in the application.

Regarding the PR objectives:

  1. The implementation of this kitchen sink example for the Drawer component is a valuable addition to the dojo.js project.
  2. However, the PR checklist items mentioned in the description have not been addressed in this file. Specifically:
    • There are no tests included in this file.
    • There's no documentation update visible here.
    • There's no indication of a dedicated CI job for the new examples.

To ensure all PR objectives are met, please verify the following:

  1. Are tests for these components implemented in a separate file?
  2. Is there documentation for these new Drawer components?
  3. Has a dedicated CI job been created for this new example?

You can use the following script to check for the existence of test and documentation files:

If these files don't exist, consider creating them to fully meet the PR objectives.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for test and documentation files

echo "Checking for test files..."
fd -e test.tsx -e test.ts -e spec.tsx -e spec.ts . examples/example-vite-kitchen-sink/src/components/ui

echo "Checking for documentation files..."
fd -e md . examples/example-vite-kitchen-sink/src/components/ui

echo "Checking for CI configuration..."
fd -e yml -e yaml . .github/workflows

Length of output: 551

Comment on lines 47 to 103
useEffect(() => {
async function getEntity(db: SDK<OnchainDashSchemaType>) {
const entity = await db.getEntities({
onchain_dash: {
Theme: { $: { where: { theme_key: { $eq: 9999999 } } } },
}
}, ({ data, error }) => { });
const counter = entity.pop();
if (!counter) {
return AvailableTheme.Light;
}

setEntityId(counter.entityId);
return AvailableTheme[counter.models.onchain_dash.Theme.value];
}
if (db) {
getEntity(db).then((th) => setTheme({ current: AvailableThemeClassMap[th], next: AvailableThemeClassMap[th] })).catch(console.error)
}
}, [address, db, setEntityId])

useEffect(() => {
async function subscribeToEntityUpdates(db: SDK<OnchainDashSchemaType>) {
const sub = await db.subscribeEntityQuery([entityId], ({ data, error }) => {
if (data) {
const entity = data.pop();
if (!entity) {
return AvailableTheme.Light;
}
if (entity.models.onchain_dash?.Theme?.value === undefined) {
return AvailableTheme.Light;
}

setTheme({ current: AvailableThemeClassMap[entity.models.onchain_dash.Theme.value], next: AvailableThemeClassMap[entity.models.onchain_dash.Theme.value] });
return AvailableTheme[entity.models.onchain_dash.Theme.value];
}
if (error) {
throw error;
}
});
setSub(sub);
}
if (entityId && db && sub === null) {
subscribeToEntityUpdates(db).then().catch(console.error)
}
}, [entityId, db, sub, theme]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider optimizing useEffect hooks and improving error handling.

The useEffect hooks handle the necessary logic for theme management, but there are some potential improvements:

  1. Consider extracting the getEntity and subscribeToEntityUpdates functions outside the useEffect to prevent unnecessary re-creation.
  2. Improve error handling by providing more specific error messages and potentially implementing a retry mechanism.
  3. The second useEffect has a dependency on theme, which might cause unnecessary re-subscriptions. Consider if this dependency is necessary.

Here's a suggested refactor for the first useEffect:

const getEntity = useCallback(async (db: SDK<OnchainDashSchemaType>) => {
  try {
    const entity = await db.getEntities({
      onchain_dash: {
        Theme: { $: { where: { theme_key: { $eq: 9999999 } } } },
      }
    });
    const counter = entity.pop();
    if (!counter) return AvailableTheme.Light;
    
    setEntityId(counter.entityId);
    return AvailableTheme[counter.models.onchain_dash.Theme.value];
  } catch (error) {
    console.error("Error fetching initial theme:", error);
    return AvailableTheme.Light;
  }
}, []);

useEffect(() => {
  if (db) {
    getEntity(db)
      .then((th) => setTheme({ current: AvailableThemeClassMap[th], next: AvailableThemeClassMap[th] }))
      .catch(console.error);
  }
}, [db, getEntity]);

Consider applying similar optimizations to the second useEffect.

Comment on lines 36 to 154
<div className="grid gap-3">
<Label htmlFor="model">Model</Label>
<Select>
<SelectTrigger
id="model"
className="items-start [&_[data-description]]:hidden"
>
<SelectValue placeholder="Select a model" />
</SelectTrigger>
<SelectContent>
<SelectItem value="genesis">
<div className="flex items-start gap-3 text-muted-foreground">
<Rabbit className="size-5" />
<div className="grid gap-0.5">
<p>
Neural{" "}
<span className="font-medium text-foreground">
Genesis
</span>
</p>
<p className="text-xs" data-description>
Our fastest model for general use cases.
</p>
</div>
</div>
</SelectItem>
<SelectItem value="explorer">
<div className="flex items-start gap-3 text-muted-foreground">
<Bird className="size-5" />
<div className="grid gap-0.5">
<p>
Neural{" "}
<span className="font-medium text-foreground">
Explorer
</span>
</p>
<p className="text-xs" data-description>
Performance and speed for efficiency.
</p>
</div>
</div>
</SelectItem>
<SelectItem value="quantum">
<div className="flex items-start gap-3 text-muted-foreground">
<Turtle className="size-5" />
<div className="grid gap-0.5">
<p>
Neural{" "}
<span className="font-medium text-foreground">
Quantum
</span>
</p>
<p className="text-xs" data-description>
The most powerful model for complex
computations.
</p>
</div>
</div>
</SelectItem>
</SelectContent>
</Select>
</div>
<div className="grid gap-3">
<Label htmlFor="temperature">Temperature</Label>
<Input id="temperature" type="number" placeholder="0.4" />
</div>
<div className="grid gap-3">
<Label htmlFor="top-p">Top P</Label>
<Input id="top-p" type="number" placeholder="0.7" />
</div>
<div className="grid gap-3">
<Label htmlFor="top-k">Top K</Label>
<Input id="top-k" type="number" placeholder="0.0" />
</div>
</fieldset>
<fieldset className="grid gap-6 rounded-lg border p-4">
<legend className="-ml-1 px-1 text-sm font-medium">
Messages
</legend>
<div className="grid gap-3">
<Label htmlFor="role">Role</Label>
<Select defaultValue="system">
<SelectTrigger>
<SelectValue placeholder="Select a role" />
</SelectTrigger>
<SelectContent>
<SelectItem value="system">System</SelectItem>
<SelectItem value="user">User</SelectItem>
<SelectItem value="assistant">Assistant</SelectItem>
</SelectContent>
</Select>
</div>
<div className="grid gap-3">
<Label htmlFor="content">Content</Label>
<Textarea id="content" placeholder="You are a..." />
</div>
</fieldset>
</form>
</DrawerContent>
</Drawer>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve accessibility in the settings drawer

The settings drawer is well-structured, but there are some accessibility improvements to be made:

  1. The Select components for "Model" and "Role" are not properly associated with their labels.
  2. The icon sizes are still using className instead of the size prop.

Please apply the following changes:

  1. For the "Model" select:
- <Select>
+ <Select id="model">
  1. For the "Role" select:
- <Select defaultValue="system">
+ <Select id="role" defaultValue="system">
  1. Update icon sizes:
- <Settings className="size-4" />
+ <Settings size={16} />

- <Rabbit className="size-5" />
+ <Rabbit size={20} />

- <Bird className="size-5" />
+ <Bird size={20} />

- <Turtle className="size-5" />
+ <Turtle size={20} />

These changes will improve the accessibility of the form and ensure proper usage of the icon components.

📝 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
<Drawer>
<DrawerTrigger asChild>
<Button variant="ghost" size="icon" className="md:hidden">
<Settings className="size-4" />
<span className="sr-only">Settings</span>
</Button>
</DrawerTrigger>
<DrawerContent className="max-h-[80vh]">
<DrawerHeader>
<DrawerTitle>Configuration</DrawerTitle>
<DrawerDescription>
Configure the settings for the model and messages.
</DrawerDescription>
</DrawerHeader>
<form className="grid w-full items-start gap-6 overflow-auto p-4 pt-0">
<fieldset className="grid gap-6 rounded-lg border p-4">
<legend className="-ml-1 px-1 text-sm font-medium">
Settings
</legend>
<div className="grid gap-3">
<Label htmlFor="model">Model</Label>
<Select>
<SelectTrigger
id="model"
className="items-start [&_[data-description]]:hidden"
>
<SelectValue placeholder="Select a model" />
</SelectTrigger>
<SelectContent>
<SelectItem value="genesis">
<div className="flex items-start gap-3 text-muted-foreground">
<Rabbit className="size-5" />
<div className="grid gap-0.5">
<p>
Neural{" "}
<span className="font-medium text-foreground">
Genesis
</span>
</p>
<p className="text-xs" data-description>
Our fastest model for general use cases.
</p>
</div>
</div>
</SelectItem>
<SelectItem value="explorer">
<div className="flex items-start gap-3 text-muted-foreground">
<Bird className="size-5" />
<div className="grid gap-0.5">
<p>
Neural{" "}
<span className="font-medium text-foreground">
Explorer
</span>
</p>
<p className="text-xs" data-description>
Performance and speed for efficiency.
</p>
</div>
</div>
</SelectItem>
<SelectItem value="quantum">
<div className="flex items-start gap-3 text-muted-foreground">
<Turtle className="size-5" />
<div className="grid gap-0.5">
<p>
Neural{" "}
<span className="font-medium text-foreground">
Quantum
</span>
</p>
<p className="text-xs" data-description>
The most powerful model for complex
computations.
</p>
</div>
</div>
</SelectItem>
</SelectContent>
</Select>
</div>
<div className="grid gap-3">
<Label htmlFor="temperature">Temperature</Label>
<Input id="temperature" type="number" placeholder="0.4" />
</div>
<div className="grid gap-3">
<Label htmlFor="top-p">Top P</Label>
<Input id="top-p" type="number" placeholder="0.7" />
</div>
<div className="grid gap-3">
<Label htmlFor="top-k">Top K</Label>
<Input id="top-k" type="number" placeholder="0.0" />
</div>
</fieldset>
<fieldset className="grid gap-6 rounded-lg border p-4">
<legend className="-ml-1 px-1 text-sm font-medium">
Messages
</legend>
<div className="grid gap-3">
<Label htmlFor="role">Role</Label>
<Select defaultValue="system">
<SelectTrigger>
<SelectValue placeholder="Select a role" />
</SelectTrigger>
<SelectContent>
<SelectItem value="system">System</SelectItem>
<SelectItem value="user">User</SelectItem>
<SelectItem value="assistant">Assistant</SelectItem>
</SelectContent>
</Select>
</div>
<div className="grid gap-3">
<Label htmlFor="content">Content</Label>
<Textarea id="content" placeholder="You are a..." />
</div>
</fieldset>
</form>
</DrawerContent>
</Drawer>
<Drawer>
<DrawerTrigger asChild>
<Button variant="ghost" size="icon" className="md:hidden">
<Settings size={16} />
<span className="sr-only">Settings</span>
</Button>
</DrawerTrigger>
<DrawerContent className="max-h-[80vh]">
<DrawerHeader>
<DrawerTitle>Configuration</DrawerTitle>
<DrawerDescription>
Configure the settings for the model and messages.
</DrawerDescription>
</DrawerHeader>
<form className="grid w-full items-start gap-6 overflow-auto p-4 pt-0">
<fieldset className="grid gap-6 rounded-lg border p-4">
<legend className="-ml-1 px-1 text-sm font-medium">
Settings
</legend>
<div className="grid gap-3">
<Label htmlFor="model">Model</Label>
<Select id="model">
<SelectTrigger
id="model"
className="items-start [&_[data-description]]:hidden"
>
<SelectValue placeholder="Select a model" />
</SelectTrigger>
<SelectContent>
<SelectItem value="genesis">
<div className="flex items-start gap-3 text-muted-foreground">
<Rabbit size={20} />
<div className="grid gap-0.5">
<p>
Neural{" "}
<span className="font-medium text-foreground">
Genesis
</span>
</p>
<p className="text-xs" data-description>
Our fastest model for general use cases.
</p>
</div>
</div>
</SelectItem>
<SelectItem value="explorer">
<div className="flex items-start gap-3 text-muted-foreground">
<Bird size={20} />
<div className="grid gap-0.5">
<p>
Neural{" "}
<span className="font-medium text-foreground">
Explorer
</span>
</p>
<p className="text-xs" data-description>
Performance and speed for efficiency.
</p>
</div>
</div>
</SelectItem>
<SelectItem value="quantum">
<div className="flex items-start gap-3 text-muted-foreground">
<Turtle size={20} />
<div className="grid gap-0.5">
<p>
Neural{" "}
<span className="font-medium text-foreground">
Quantum
</span>
</p>
<p className="text-xs" data-description>
The most powerful model for complex
computations.
</p>
</div>
</div>
</SelectItem>
</SelectContent>
</Select>
</div>
<div className="grid gap-3">
<Label htmlFor="temperature">Temperature</Label>
<Input id="temperature" type="number" placeholder="0.4" />
</div>
<div className="grid gap-3">
<Label htmlFor="top-p">Top P</Label>
<Input id="top-p" type="number" placeholder="0.7" />
</div>
<div className="grid gap-3">
<Label htmlFor="top-k">Top K</Label>
<Input id="top-k" type="number" placeholder="0.0" />
</div>
</fieldset>
<fieldset className="grid gap-6 rounded-lg border p-4">
<legend className="-ml-1 px-1 text-sm font-medium">
Messages
</legend>
<div className="grid gap-3">
<Label htmlFor="role">Role</Label>
<Select id="role" defaultValue="system">
<SelectTrigger>
<SelectValue placeholder="Select a role" />
</SelectTrigger>
<SelectContent>
<SelectItem value="system">System</SelectItem>
<SelectItem value="user">User</SelectItem>
<SelectItem value="assistant">Assistant</SelectItem>
</SelectContent>
</Select>
</div>
<div className="grid gap-3">
<Label htmlFor="content">Content</Label>
<Textarea id="content" placeholder="You are a..." />
</div>
</fieldset>
</form>
</DrawerContent>
</Drawer>

Comment on lines 23 to 28
const walletIdToName = new Map([
["argentX", "Argent X"],
["braavos", "Braavos"],
["argentWebWallet", "Email"],
["argentMobile", "Argent mobile"],
]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider moving walletIdToName to a separate configuration file.

While the walletIdToName mapping is well-defined, it might be beneficial to extract it to a separate configuration file. This would improve maintainability and allow for potential reuse across different components.

You could create a new file, e.g., src/config/wallets.ts:

export const walletIdToName = new Map([
  ["argentX", "Argent X"],
  ["braavos", "Braavos"],
  ["argentWebWallet", "Email"],
  ["argentMobile", "Argent mobile"],
]);

Then import it in this file:

import { walletIdToName } from "@/config/wallets";

This approach would make it easier to update wallet configurations in the future and potentially reuse this mapping in other parts of the application.

<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider Respecting Users' Reduced Motion Preferences

The animations applied to DialogOverlay and DialogContent may not respect users who have enabled reduced motion settings. Consider wrapping the animation classes with Tailwind's motion-safe modifier to enhance accessibility.

Apply the following changes:

For DialogOverlay (line 22):

- "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
+ "fixed inset-0 z-50 bg-black/80 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=open]:fade-in-0"

For DialogContent (line 39):

- "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg"
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:zoom-in-95 motion-safe:data-[state=closed]:slide-out-to-left-1/2 motion-safe:data-[state=closed]:slide-out-to-top-[48%] motion-safe:data-[state=open]:slide-in-from-left-1/2 motion-safe:data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg"

Also applies to: 39-39

Copy link

@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: 10

🧹 Outside diff range and nitpick comments (19)
examples/example-vite-kitchen-sink/src/config.ts (1)

1-1: Add a brief comment explaining the configuration's purpose

To improve code maintainability, consider adding a brief comment explaining the purpose of this configuration file.

Here's a suggested comment to add at the beginning of the file:

/**
 * Application configuration
 * This file contains centralized configuration for various external links related to the Dojo engine.
 */

This comment will help other developers quickly understand the purpose of this configuration file.

examples/example-vite-kitchen-sink/src/app/layout.tsx (2)

1-7: Consider removing the empty line between imports.

For consistency in code style, consider removing the empty line (line 7) between the import statements. This helps maintain a clean and uniform import section.

 import StarknetProvider from "@/components/starknet-provider";
-

8-22: Approve component structure with a minor suggestion for accessibility.

The RootLayout component is well-structured and follows React best practices. The use of providers and the grid layout with sidebar and header is effective.

To improve accessibility, consider adding a main tag around the children to clearly define the main content area.

 <div className="flex flex-col">
   <Header />
-  {children}
+  <main>{children}</main>
 </div>
🧰 Tools
🪛 Biome

[error] 8-8: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

examples/example-vite-kitchen-sink/netlify.toml (3)

7-12: Consider adding a note about SPA configuration.

The commented-out redirect rule for Single Page Applications (SPAs) is a good inclusion. To improve clarity for future developers or deployments, consider adding a brief note explaining when this section should be uncommented. For example:

# Uncomment the following section if this is a Single Page Application (SPA)
# This will route all requests to index.html, which is necessary for client-side routing
#[[redirects]]
#  from = "/*"
#  to = "/index.html"
#  status = 200

This addition will help prevent confusion and make it easier to configure the file correctly for different project types.


21-21: Add a note about the configuration link.

The inclusion of a link for more information on configuring the netlify.toml file is helpful. However, the use of a short URL (ntl.fyi) might not be immediately recognizable as an official Netlify resource. Consider adding a brief note to clarify this:

# For more information on configuring this file, visit the official Netlify documentation:
# https://ntl.fyi/file-based-build-config

This change provides context for the link and assures users that it's an official resource.


1-21: Overall assessment: Good start, but more work needed to meet PR objectives.

This netlify.toml file is a good start for configuring the deployment of your kitchen sink example. It provides essential build settings and includes commented sections for SPA and Netlify Dev configurations, which adds flexibility for different use cases.

However, in relation to the PR objectives:

  1. The PR checklist mentions creating a dedicated CI job for the new examples. This configuration file doesn't address that requirement. Consider adding CI-specific configurations or creating a separate CI configuration file.

  2. The checklist also mentions updating documentation and adding tests. Ensure that you've addressed these items in other files or consider adding comments in this file to point to relevant documentation or test files.

  3. The "self-review" item on the checklist should now be possible to complete with this configuration in place.

Remember to update the PR description with any relevant information about this configuration file and how it contributes to the kitchen sink example. Also, consider linking any related issues if they exist.

examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (3)

1-13: Remove unused imports to improve code cleanliness.

The imports from @starknet-react/core include argent and braavos, which are not used in this file. Consider removing these unused imports to keep the code clean and potentially improve performance.

Apply this diff to remove the unused imports:

 import {
-  argent,
-  braavos,
   jsonRpcProvider,
   StarknetConfig,
   useInjectedConnectors,
   voyager,
 } from "@starknet-react/core";

15-32: CartridgeConnector configuration looks good, consider extracting policies.

The CartridgeConnector configuration is well-structured and uses environment variables appropriately. To improve readability and maintainability, consider extracting the policies into a separate constant or configuration file.

Here's a suggested refactor:

// In a separate file, e.g., cartridgePolicies.ts
export const cartridgePolicies = [
  {
    target: dojoConfig.manifest.contracts[0].address,
    method: 'increment_caller_counter',
  },
  {
    target: dojoConfig.manifest.contracts[0].address,
    method: 'increment_global_counter',
  },
  {
    target: dojoConfig.manifest.contracts[0].address,
    method: 'change_theme',
  },
];

// In starknet-provider.tsx
import { cartridgePolicies } from './cartridgePolicies';

const cartridge = new CartridgeConnector({
  url: env.VITE_CONTROLLER_URL,
  rpc: env.VITE_CONTROLLER_RPC,
  policies: cartridgePolicies,
});

This approach would make the main file cleaner and allow for easier management of policies.


34-54: StarknetProvider component looks good, consider making autoConnect configurable.

The StarknetProvider component is well-structured and correctly implements the StarknetConfig wrapper. The use of jsonRpcProvider with a custom RPC URL is appropriate.

Consider making the autoConnect prop configurable by passing it as a prop to the StarknetProvider component. This would allow more flexibility in different usage scenarios. Here's a suggested modification:

interface StarknetProviderProps extends PropsWithChildren {
  autoConnect?: boolean;
}

export default function StarknetProvider({ children, autoConnect = true }: StarknetProviderProps) {
  // ... existing code ...

  return (
    <StarknetConfig
      // ... other props ...
      autoConnect={autoConnect}
    >
      {children}
    </StarknetConfig>
  );
}

This change allows users of the StarknetProvider to decide whether they want auto-connection enabled or not.

examples/example-vite-kitchen-sink/src/dojo/models.ts (4)

1-26: LGTM! Consider adding JSDoc comments for better documentation.

The import statement and interface definitions are well-structured and follow TypeScript best practices. The use of fieldOrder in each interface ensures consistent field ordering, which is a good practice.

Consider adding JSDoc comments to each interface to provide more context and improve documentation. For example:

/**
 * Represents a global counter in the onchain dashboard.
 */
export interface GlobalCounter {
  // ... existing properties
}

28-38: LGTM! Consider using enum values as keys for improved type safety.

The AvailableTheme enum and AvailableThemeClassMap are well-defined and provide a useful mapping between theme values and CSS classes.

For improved type safety, consider using enum values as keys in AvailableThemeClassMap:

export const AvailableThemeClassMap: Record<AvailableTheme, string> = {
  [AvailableTheme.Light]: 'light',
  [AvailableTheme.Dark]: 'dark',
  [AvailableTheme.Dojo]: 'dojo'
};

This change ensures that all enum values are mapped and prevents accidental use of invalid keys.


1-1: Consider adding a file-level JSDoc comment for better documentation.

The file structure is clean and exports a comprehensive set of types and values for the kitchen sink example. To improve documentation, consider adding a file-level JSDoc comment at the beginning of the file to explain its purpose and contents.

Add a file-level JSDoc comment like this:

/**
 * @file This module defines the data models and schema for the Dojo.js kitchen sink example.
 * It includes interfaces for various counters, themes, and messages, as well as the overall schema structure.
 */

1-76: Great foundation for the kitchen sink example. Consider next steps.

This file provides a solid foundation for the kitchen sink example with well-structured interfaces, enums, and a schema. The code is consistent, follows TypeScript best practices, and aligns well with the PR objectives.

To complete the kitchen sink example, consider the following next steps:

  1. Implement components that utilize these models and schema.
  2. Create example usage of the Dojo Engine SDK with this schema.
  3. Add unit tests to ensure the correctness of the schema and any related functionality.
  4. Update the project documentation to explain how to use this kitchen sink example.
  5. As mentioned in the PR checklist, create a dedicated CI job for this new example.

These steps will help ensure that the kitchen sink example is comprehensive, well-tested, and easy for other developers to understand and use.

examples/example-vite-kitchen-sink/src/components/ui/button.tsx (3)

8-35: LGTM! Consider minor consistency improvement

The button variants definition is well-structured and covers a good range of use cases. The use of cva allows for flexible and maintainable styling.

For consistency, consider using object shorthand notation for the default size variant:

 size: {
-  default: "h-10 px-4 py-2",
+  default: "h-10 px-4 py-2",
   sm: "h-9 rounded-md px-3",
   lg: "h-11 rounded-md px-8",
   icon: "h-10 w-10",
 },

This change aligns with the syntax used for other variants.


37-42: LGTM! Consider adding JSDoc comments

The ButtonProps interface is well-defined and includes useful custom props. To improve developer experience, consider adding JSDoc comments for the custom props:

 export interface ButtonProps
   extends React.ButtonHTMLAttributes<HTMLButtonElement>,
   VariantProps<typeof buttonVariants> {
+  /** If true, the component will be rendered as its child */
   asChild?: boolean
+  /** If true, the button will display a loading indicator */
   loading?: boolean
 }

These comments will provide helpful tooltips in IDEs supporting JSDoc.


44-60: LGTM! Consider performance optimizations

The Button component implementation is solid and handles various cases well. The use of forwardRef and the handling of the asChild prop provide great flexibility.

To potentially improve performance, consider these optimizations:

  1. Memoize the component to prevent unnecessary re-renders:
-const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
+const Button = React.memo(React.forwardRef<HTMLButtonElement, ButtonProps>(
   ({ className, variant, size, asChild = false, children, loading, ...props }, ref) => {
     // ... component implementation ...
   }
-)
+))
  1. Use useCallback for the returned JSX to further optimize renders:
 const Button = React.memo(React.forwardRef<HTMLButtonElement, ButtonProps>(
   ({ className, variant, size, asChild = false, children, loading, ...props }, ref) => {
     const Comp = asChild ? Slot : "button"
-    return (
+    return React.useCallback((
       <Comp
         className={cn(buttonVariants({ variant, size, className }))}
         ref={ref}
         disabled={props.disabled ?? loading}
         {...props}
       >
         {loading && <ReloadIcon className="mr-2 h-4 w-4 animate-spin" />}
         {children}
       </Comp>
-    )
+    ), [className, variant, size, asChild, children, loading, props, ref])
   }
 ))

These optimizations can help reduce unnecessary re-renders in complex applications.

examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (2)

36-36: TODO comment needs to be addressed.

There's an empty line with a TODO comment. Please ensure this is addressed before finalizing the PR.

Would you like me to create a GitHub issue to track this TODO item?


112-141: Rendering logic looks good, consider adding aria-labels for accessibility.

The component's rendering is well-structured and makes good use of the design system components. The dropdown items correctly map to the available themes and trigger the appropriate actions.

To improve accessibility, consider adding aria-labels to the dropdown menu items. For example:

- <DropdownMenuItem onClick={() => handleChangeTheme(AvailableTheme.Light)}>
+ <DropdownMenuItem onClick={() => handleChangeTheme(AvailableTheme.Light)} aria-label="Switch to light theme">

Apply similar changes to the other theme options.

examples/example-vite-kitchen-sink/src/components/chat.tsx (1)

105-142: LGTM with a minor suggestion for accessibility improvement.

The component rendering is well-structured, with appropriate use of UI components and correct handling of form submission and message display.

Consider adding an aria-label to the form element to improve accessibility:

- <form ref={formRef} className="relative flex h-full min-h-[50vh] flex-col rounded-xl bg-muted/50 p-4 lg:col-span-2" onSubmit={handleSubmit((data) => publish(data))} onKeyPress={handleKeyPress}>
+ <form ref={formRef} className="relative flex h-full min-h-[50vh] flex-col rounded-xl bg-muted/50 p-4 lg:col-span-2" onSubmit={handleSubmit((data) => publish(data))} onKeyPress={handleKeyPress} aria-label="Chat message form">

This addition will help screen readers better understand the purpose of the form.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 4104f89 and 00427bc.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (17)
  • .gitignore (1 hunks)
  • examples/example-vite-kitchen-sink/.gitignore (1 hunks)
  • examples/example-vite-kitchen-sink/netlify.toml (1 hunks)
  • examples/example-vite-kitchen-sink/package.json (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/layout.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/chat.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/header.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/models.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/env.ts (1 hunks)
  • examples/example-vite-kitchen-sink/tsconfig.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (7)
  • examples/example-vite-kitchen-sink/.gitignore
  • examples/example-vite-kitchen-sink/package.json
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/header.tsx
  • examples/example-vite-kitchen-sink/src/env.ts
  • examples/example-vite-kitchen-sink/tsconfig.json
🧰 Additional context used
🪛 Biome
examples/example-vite-kitchen-sink/src/app/layout.tsx

[error] 8-8: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🔇 Additional comments (16)
examples/example-vite-kitchen-sink/src/config.ts (2)

1-8: LGTM: Clear and concise configuration structure

The overall structure and content of the configuration look good. It provides a clean and centralized way to manage important links related to the Dojo engine.

The use of a configuration object for managing links is a good practice. It will make it easier to update these links in the future and use them consistently across the application.


1-8: Verify indentation style

The current indentation uses 2 spaces, which is common in many JavaScript/TypeScript projects. However, it's important to ensure this aligns with the project's style guide.

Please run the following script to check the project's indentation style:

If the results show inconsistencies or if there's no defined style in .editorconfig, consider establishing a consistent indentation style across the project.

examples/example-vite-kitchen-sink/src/app/layout.tsx (1)

1-22: Overall, the RootLayout component is well-implemented.

The RootLayout component provides a solid foundation for the kitchen sink example. It effectively wraps the application with necessary providers and establishes a clear layout structure. The minor suggestions provided will further enhance code quality and accessibility.

To fully align with the PR objectives:

  1. Ensure that this example is thoroughly tested.
  2. Update relevant documentation to explain the purpose and usage of this kitchen sink example.
  3. Consider creating a dedicated CI job for this new example, as mentioned in the PR checklist.

Let's verify if the documentation has been updated for this new example:

🧰 Tools
🪛 Biome

[error] 8-8: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

examples/example-vite-kitchen-sink/netlify.toml (1)

2-5: LGTM! Verify the publish directory path.

The build settings look good. The use of pnpm for the build command is appropriate for modern JavaScript projects. However, please verify that the publish directory path examples/example-vite-kitchen-sink/dist is correct, as it seems to be nested quite deeply. This might be intentional if you're using a monorepo structure, but it's worth double-checking to ensure it accurately points to your built files.

examples/example-vite-kitchen-sink/src/dojo/models.ts (2)

40-47: LGTM! The OnchainDashSchemaType is well-structured.

The OnchainDashSchemaType interface correctly extends SchemaType from the SDK and includes all the previously defined interfaces. This structure ensures consistency and type safety when working with the schema.


49-75: LGTM! Please clarify the use of 9999999 as a key.

The schema constant is well-structured and provides appropriate default values for all fields. This is good for initialization and matches the OnchainDashSchemaType interface.

Could you please explain the significance of using 9999999 as the key for global_counter_key and theme_key? If this is an arbitrary choice, consider using a more meaningful constant or documenting the reason for this specific value.

examples/example-vite-kitchen-sink/src/components/ui/button.tsx (2)

62-62: LGTM! Exports are clear and flexible

The export statement is concise and provides good flexibility by exporting both the Button component and the buttonVariants. This allows users of the module to use the pre-defined styles separately if needed.


1-6: 🛠️ Refactor suggestion

Consider optimizing imports for better tree-shaking

The current React import uses the * syntax, which may hinder tree-shaking. Consider updating it to import only the necessary parts:

-import * as React from "react"
+import React, { forwardRef } from "react"

Also, ensure that the path alias @/ is properly configured in your project setup for the import from "@/lib/utils".

To verify the path alias configuration, run the following command:

examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (2)

1-24: Imports and interface declaration look good.

The necessary dependencies are imported, and the ThemeState interface is well-defined. This provides a solid foundation for the component.


26-35: Component initialization and state management look good.

The component is properly structured with appropriate state variables and hooks. The use of useContractWrite for contract interactions is a good practice.

examples/example-vite-kitchen-sink/src/components/chat.tsx (4)

1-24: LGTM: Imports and type definitions are well-structured.

The imports cover all necessary dependencies for the component's functionality, and the interfaces are clearly defined. This provides a solid foundation for the component.


26-33: LGTM: Component initialization and state management are well-implemented.

The Chat component is properly set up with appropriate hooks for form management, account handling, and local state. The use of a ref for the form element is a good practice for direct DOM manipulation when needed.


52-90: LGTM: Message fetching and real-time updates are well-implemented.

The useEffect hooks for fetching existing messages and subscribing to updates are implemented correctly. They ensure that messages are retrieved and displayed in chronological order, and that new messages are added in real-time.


92-103: LGTM: handleKeyPress function is well-implemented.

The handleKeyPress function correctly handles the Enter key press for form submission, allowing for a smooth user experience. It properly distinguishes between Enter for submission and Shift+Enter for new line.

examples/example-vite-kitchen-sink/src/components/sidebar.tsx (2)

99-99: Correct the aria-label for the Help button

The aria-label for the Help button is correctly set to "Help". However, to maintain consistency with the previous review comment about the Account button, it's worth noting that this label is correct and doesn't need to be changed.


1-166: Summary of Sidebar Component Review

The new Sidebar component successfully implements the kitchen sink example as part of the PR objectives. It provides a comprehensive UI for navigation and wallet connection, which aligns well with the goals of the dojo.js project.

Key points:

  1. The component structure is generally well-organized and follows React best practices.
  2. Wallet connection functionality is implemented using the @starknet-react/core library.
  3. The UI includes tooltips and a modal dialog for improved user experience.

Recommendations for improvement:

  1. Enhance error handling and user feedback for wallet connection attempts.
  2. Optimize the nesting of Tooltip and Dialog components for better readability.
  3. Implement safeguards for potentially undefined connector icons.
  4. Ensure consistent and correct use of aria-labels for accessibility.

These improvements will further enhance the quality and robustness of the kitchen sink example. Once these changes are implemented, the component will serve as an excellent demonstration of dojo.js capabilities.

Comment on lines +1 to +8
export const appConfig = {
links: {
github: 'https://github.com/dojoengine/dojo.js',
x: 'https://x.com/ohayo_dojo',
discord: 'https://discord.gg/vUN4Xq9Qv6',
doc: 'https://book.dojoengine.org',
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add type definitions for better type safety

While the structure is clear, adding type definitions would enhance type safety and provide better auto-completion in IDEs. Consider defining an interface for the appConfig object.

Here's a suggested implementation with type definitions:

interface AppLinks {
  github: string;
  x: string;
  discord: string;
  doc: string;
}

interface AppConfig {
  links: AppLinks;
}

export const appConfig: AppConfig = {
  links: {
    github: 'https://github.com/dojoengine/dojo.js',
    x: 'https://x.com/ohayo_dojo',
    discord: 'https://discord.gg/vUN4Xq9Qv6',
    doc: 'https://book.dojoengine.org',
  }
};

This change will provide better type checking and auto-completion for future use of appConfig.

import StarknetProvider from "@/components/starknet-provider";


export default function RootLayout({ children }: React.PropsWithChildren<{}>) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Simplify the type definition for RootLayout.

To address the static analysis hint and improve type clarity, you can simplify the type definition for RootLayout. Since no additional props are used besides children, you can use React.PropsWithChildren without the empty object type.

-export default function RootLayout({ children }: React.PropsWithChildren<{}>) {
+export default function RootLayout({ children }: React.PropsWithChildren) {
📝 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
export default function RootLayout({ children }: React.PropsWithChildren<{}>) {
export default function RootLayout({ children }: React.PropsWithChildren) {
🧰 Tools
🪛 Biome

[error] 8-8: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

Comment on lines +14 to +19
## (optional) Settings for Netlify Dev
## https://github.com/netlify/cli/blob/main/docs/netlify-dev.md#project-detection
#[dev]
# command = "yarn start" # Command to start your dev server
# port = 3000 # Port that the dev server will be listening on
# publish = "dist" # Folder with the static content for _redirect file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Update Netlify Dev command for consistency.

The Netlify Dev settings section is a helpful inclusion for local development. However, there's an inconsistency in the package manager used. The build command uses pnpm, but the Netlify Dev command uses yarn. For consistency, consider updating the command to use pnpm:

  #[dev]
- #  command = "yarn start" # Command to start your dev server
+ #  command = "pnpm start" # Command to start your dev server
  #  port = 3000 # Port that the dev server will be listening on
  #  publish = "dist" # Folder with the static content for _redirect file

This change will ensure that the same package manager is used throughout the configuration, reducing potential confusion or errors.

📝 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
## (optional) Settings for Netlify Dev
## https://github.com/netlify/cli/blob/main/docs/netlify-dev.md#project-detection
#[dev]
# command = "yarn start" # Command to start your dev server
# port = 3000 # Port that the dev server will be listening on
# publish = "dist" # Folder with the static content for _redirect file
## (optional) Settings for Netlify Dev
## https://github.com/netlify/cli/blob/main/docs/netlify-dev.md#project-detection
#[dev]
# command = "pnpm start" # Command to start your dev server
# port = 3000 # Port that the dev server will be listening on
# publish = "dist" # Folder with the static content for _redirect file

Comment on lines +1 to +54
import type { PropsWithChildren } from "react";
import CartridgeConnector from "@cartridge/connector";
import { Chain, mainnet } from "@starknet-react/chains";
import {
argent,
braavos,
jsonRpcProvider,
StarknetConfig,
useInjectedConnectors,
voyager,
} from "@starknet-react/core";
import { env, getRpcUrl } from "@/env";
import { dojoConfig } from "@/dojo.config";

const cartridge = new CartridgeConnector({
url: env.VITE_CONTROLLER_URL,
rpc: env.VITE_CONTROLLER_RPC,
policies: [
{
target: dojoConfig.manifest.contracts[0].address,
method: 'increment_caller_counter',
},
{
target: dojoConfig.manifest.contracts[0].address,
method: 'increment_global_counter',
},
{
target: dojoConfig.manifest.contracts[0].address,
method: 'change_theme',
},
]
});

export default function StarknetProvider({ children }: PropsWithChildren) {
const provider = jsonRpcProvider({
rpc: (
chain: Chain
) => ({ nodeUrl: getRpcUrl() })
});

return (
<StarknetConfig
chains={[mainnet]}
provider={provider}
connectors={[
cartridge,
]}
explorer={voyager}
autoConnect
>
{children}
</StarknetConfig>
);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Documentation Missing StarknetProvider Information

The documentation does not include mentions of the StarknetProvider component. Please update the documentation to reflect the addition of this new component.

  • Add explanations and usage examples for StarknetProvider in the README or relevant documentation files.
🔗 Analysis chain

Overall implementation looks good, remember to complete PR checklist items.

The StarknetProvider component is well-implemented and serves as a good addition to the kitchen sink example. It provides the necessary configuration for interacting with the StarkNet blockchain in a React application.

As per the PR objectives, please ensure that you complete the following checklist items:

  1. Update documentation to explain the usage of this new component.
  2. Add tests to verify the component's behavior.
  3. Create a dedicated CI job for the new examples, if not already done.
  4. Perform a self-review of your code.

To help verify the documentation status, you can run the following script:

This script will help identify if documentation has been updated to include information about the new StarknetProvider component.


To ensure that the documentation for StarknetProvider is properly updated, please run the following script:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for documentation updates related to StarknetProvider

# Test: Search for documentation mentioning StarknetProvider
# Expect: Occurrences in markdown files or comments explaining its usage
rg --type md --type tsx --type ts "StarknetProvider"

# Test: Check for updates in README or documentation files
# Expect: Recent changes in documentation files
git diff HEAD~5 -- "*.md" "docs/*"

Length of output: 1905


Script:

#!/bin/bash
# Description: Check for documentation updates related to StarknetProvider

# Test: Search for documentation mentioning StarknetProvider in markdown and tsx files
rg --type md --type tsx "StarknetProvider"

# Test: Check for updates in README or documentation files
git diff HEAD~5 -- "*.md" "docs/*"

Length of output: 1895

Comment on lines +49 to +103
useEffect(() => {
async function getEntity(db: SDK<OnchainDashSchemaType>): Promise<AvailableTheme> {
const entity = await db.getEntities({
onchain_dash: {
Theme: { $: { where: { theme_key: { $eq: 9999999 } } } },
}
}, () => { });
const counter = entity.pop();
if (!counter) {
return AvailableTheme.Light;
}

const theme = counter.models?.onchain_dash?.Theme?.value;
setEntityId(counter.entityId);
if (undefined === theme) {
return AvailableTheme.Light;
}
// @ts-expect-error this resooves to enum value
return AvailableTheme[theme];
}
if (db) {
getEntity(db).then((th: AvailableTheme) => setTheme({ current: AvailableThemeClassMap[th], next: AvailableThemeClassMap[th] })).catch(console.error)
}
}, [address, db, setEntityId])

useEffect(() => {
async function subscribeToEntityUpdates(db: SDK<OnchainDashSchemaType>) {
// @ts-expect-error we should be able to use ['entityId'] here
const sub = await db.subscribeEntityQuery([entityId], ({ data, error }) => {
if (data) {
const entity = data.pop();
if (!entity) {
return AvailableTheme.Light;
}
if (entity.models.onchain_dash?.Theme?.value === undefined) {
return AvailableTheme.Light;
}
const theme = entity.models?.onchain_dash?.Theme?.value;

const at = AvailableTheme[theme];
// @ts-expect-error this resooves to enum value
setTheme({ current: AvailableThemeClassMap[at], next: AvailableThemeClassMap[at] });
setIsLoading(false);
return AvailableTheme[entity.models.onchain_dash.Theme.value];
}
if (error) {
throw error;
}
});
setSub(sub);
}
if (entityId && db && sub === null) {
subscribeToEntityUpdates(db).then().catch(console.error)
}
}, [entityId, db, sub, theme]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider refactoring useEffect hooks for improved maintainability and type safety.

The useEffect hooks are handling complex logic for fetching and subscribing to theme data. Consider the following improvements:

  1. Extract the getEntity and subscribeToEntityUpdates functions outside the useEffect hooks to improve readability and reusability.
  2. Address TypeScript errors and avoid using @ts-expect-error. Instead, properly type the responses from the database.
  3. Improve error handling by providing more specific error messages and potentially implementing a retry mechanism.
  4. Consider using a custom hook to encapsulate this logic, improving separation of concerns.

Example refactor for getEntity:

const getEntity = useCallback(async (db: SDK<OnchainDashSchemaType>): Promise<AvailableTheme> => {
  try {
    const entity = await db.getEntities({
      onchain_dash: {
        Theme: { $: { where: { theme_key: { $eq: 9999999 } } } },
      }
    });
    const counter = entity.pop();
    if (!counter) return AvailableTheme.Light;
    
    setEntityId(counter.entityId);
    const theme = counter.models?.onchain_dash?.Theme?.value;
    return theme !== undefined ? AvailableTheme[theme as keyof typeof AvailableTheme] : AvailableTheme.Light;
  } catch (error) {
    console.error("Error fetching initial theme:", error);
    return AvailableTheme.Light;
  }
}, []);

Apply similar refactoring to subscribeToEntityUpdates and consider creating a custom hook for managing theme state and subscriptions.

Comment on lines +105 to +110
useEffect(() => {
document.body.classList.forEach((cls) => document.body.classList.remove(cls));
if (null !== theme.next) {
document.body.classList.add(theme.next);
}
}, [theme]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize theme application logic.

The current implementation removes all classes from the document body before applying the new theme. This approach might unintentionally remove non-theme related classes. Consider a more targeted approach:

useEffect(() => {
  const validThemes = Object.values(AvailableThemeClassMap);
  document.body.classList.remove(...validThemes);
  if (theme.next && validThemes.includes(theme.next)) {
    document.body.classList.add(theme.next);
  }
}, [theme.next]);

This refactored version only removes known theme classes and ensures that only valid theme classes are added. Also, consider if you need to handle both theme.current and theme.next, or if theme.next alone is sufficient.

Comment on lines +34 to +51
const publish = useCallback(async (data: FormValues) => {
if (!account || !db) return;

const asciiMessage = toValidAscii(data.message);
const msg = db.generateTypedData('onchain_dash-Message', { identity: account?.address, content: asciiMessage, timestamp: Date.now() })
try {
const signature = await account.signMessage(msg);

try {
await db.client.publishMessage(JSON.stringify(msg), signature as string[]);
reset();
} catch (error) {
console.error("failed to publish message:", error);
}
} catch (error) {
console.error("failed to sign message:", error);
}
}, [db, account, reset]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance error handling in the publish function.

While the current implementation includes basic error logging, it could be improved to provide a better user experience. Consider implementing user-friendly error messages or notifications.

Here's an example of how you could enhance the error handling:

import { toast } from 'your-preferred-toast-library';

// In the publish function
try {
  await db.client.publishMessage(JSON.stringify(msg), signature as string[]);
  reset();
  toast.success("Message sent successfully!");
} catch (error) {
  console.error("Failed to publish message:", error);
  toast.error("Failed to send message. Please try again.");
}

This approach provides visual feedback to the user about the success or failure of their action.

Comment on lines +30 to +42
const connect = useCallback(async (connector: Connector) => {
setModalEnabled(false)
setPendingConnectorId(connector.id);
try {
await connectAsync({ connector });
setModalOpen(false);
} catch (error) {
setModalOpen(true);
setModalEnabled(true);
console.error(error);
}
setPendingConnectorId(undefined);
}, [connectAsync, setModalOpen]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance error handling and user feedback in the connect function

While the connect function handles errors by logging them to the console, it could be improved to provide better user feedback. Consider implementing the following enhancements:

  1. Add a state variable for error messages:
const [errorMessage, setErrorMessage] = useState<string | null>(null);
  1. Update the connect function to set and clear error messages:
const connect = useCallback(async (connector: Connector) => {
  setModalEnabled(false);
  setPendingConnectorId(connector.id);
  setErrorMessage(null);
  try {
    await connectAsync({ connector });
    setModalOpen(false);
  } catch (error) {
    setModalOpen(true);
    setModalEnabled(true);
    setErrorMessage("Failed to connect. Please try again.");
    console.error(error);
  }
  setPendingConnectorId(undefined);
}, [connectAsync, setModalOpen]);
  1. Display the error message in the DialogContent component (implementation details to be added later in the review).

These changes will improve the user experience by providing clear feedback when connection attempts fail.

Comment on lines +109 to +162
<Tooltip>
<Dialog modal={modalEnabled} open={modalOpen} onOpenChange={setModalOpen}>
<TooltipTrigger asChild>
<DialogTrigger asChild>
<Button
variant="ghost"
size="icon"
className="mt-auto rounded-lg"
aria-label="Help"
>
<SquareUser className="size-5" />
</Button>
</DialogTrigger>
</TooltipTrigger>
<TooltipContent side="right" sideOffset={5}>
Account
</TooltipContent>

<DialogContent>
<DialogHeader>
<DialogTitle>Choose the wallet you want to use</DialogTitle>
</DialogHeader>
<DialogDescription className="grid gap-2 p-4">
{connectors.map((connector) => {
return (
<Button
key={connector.id}
onClick={() => connect(connector)}
variant="secondary"
className="relative pl-12 flex"
>
<div className="absolute left-2 top-1/2 flex size-8 -translate-y-1/2 items-center justify-center rounded-xs bg-background">
<img
src={
connector.icon.dark
}
className="size-5"
alt={`${connector.name}`}
/>
</div>
{connector.name}
{isWalletConnecting(connector.id) && (
<Loader
className="absolute right-2.5 top-3 animate-spin"
size={24}
/>
)}
</Button>
);
})}
</DialogDescription>
</DialogContent>
</Dialog>
</Tooltip>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize component structure and enhance error handling

  1. Simplify the nesting of Tooltip and Dialog components:
    Consider restructuring the components to reduce nesting and improve readability. For example:

    <Tooltip>
      <Dialog modal={modalEnabled} open={modalOpen} onOpenChange={setModalOpen}>
        <TooltipTrigger asChild>
          <DialogTrigger asChild>
            <Button
              variant="ghost"
              size="icon"
              className="mt-auto rounded-lg"
              aria-label="Account"
            >
              <SquareUser className="size-5" />
            </Button>
          </DialogTrigger>
        </TooltipTrigger>
        {/* DialogContent here */}
      </Dialog>
      <TooltipContent side="right" sideOffset={5}>
        Account
      </TooltipContent>
    </Tooltip>
  2. Handle potential undefined connector icons:
    Modify the img tag to prevent broken images:

    {connector.icon.dark ? (
      <img
        src={connector.icon.dark}
        className="size-5"
        alt={`${connector.name}`}
      />
    ) : (
      <DefaultIcon className="size-5" />
    )}

    Ensure you import or define a DefaultIcon component to use as a fallback.

  3. Display error messages in the DialogContent:
    Add error message display within the DialogContent:

    <DialogContent>
      {/* ... existing content ... */}
      {errorMessage && (
        <p className="text-red-500 mt-2">{errorMessage}</p>
      )}
      {/* ... rest of the content ... */}
    </DialogContent>

These changes will improve the component's structure, error handling, and user feedback.

Copy link

@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: 13

🧹 Outside diff range and nitpick comments (17)
examples/example-vite-kitchen-sink/src/app/layout.tsx (1)

9-22: LGTM: Well-structured layout implementation.

The RootLayout component is well-implemented, providing necessary providers and a logical structure for the application layout. The use of StarknetProvider and TooltipProvider ensures proper context for child components.

Consider extracting the layout structure (grid, sidebar, and header) into a separate component for improved modularity. This could make the RootLayout more focused on providing context and easier to maintain. For example:

const LayoutStructure: React.FC<React.PropsWithChildren> = ({ children }) => (
  <div className="grid h-screen w-full pl-[53px]">
    <Sidebar />
    <div className="flex flex-col">
      <Header />
      {children}
    </div>
  </div>
);

export default function RootLayout({ children }: React.PropsWithChildren) {
  return (
    <StarknetProvider>
      <TooltipProvider delayDuration={400}>
        <LayoutStructure>{children}</LayoutStructure>
      </TooltipProvider>
    </StarknetProvider>
  );
}

This refactoring is optional but could enhance the maintainability of your code.

examples/example-vite-kitchen-sink/src/app/page.tsx (4)

1-10: Remove unused imports or add TODO comments for future use.

The following imports are not used in the visible code:

  • useDojoDb
  • useEffect
  • useState
  • OnchainDashSchemaType
  • SDK
  • Subscription

Consider removing these unused imports to improve code clarity and potentially reduce bundle size. If they are intended for future use, add TODO comments explaining their purpose.


16-34: Implement settings and stats sections or add TODO comments.

The settings section is currently empty, and the stats section contains only placeholder text. To align with the PR objectives and improve the completeness of the kitchen sink example:

  1. Implement actual settings in the settings section or add a TODO comment explaining what settings are planned.
  2. Replace the placeholder text in the stats section with actual statistics or add a TODO comment describing the intended stats.

Example:

<fieldset className="grid gap-6 rounded-lg border p-4">
  <legend className="-ml-1 px-1 text-sm font-medium">
    Settings
  </legend>
  <div className="grid gap-3">
    {/* TODO: Implement settings such as theme toggle, notification preferences, etc. */}
  </div>
</fieldset>

// ... (other code)

<fieldset className="grid gap-6 rounded-lg border p-4">
  <legend className="-ml-1 px-1 text-sm font-medium">
    Stats
  </legend>
  <div className="grid gap-3">
    {/* TODO: Display actual statistics such as user activity, system performance, etc. */}
  </div>
</fieldset>

This will help track the remaining work and provide a clearer picture of the intended functionality.


35-39: Approve Chat component inclusion and consider configuration options.

The inclusion of the Chat component in the kitchen sink example is appropriate. However, consider the following suggestions:

  1. If the Chat component supports configuration options, consider passing them as props to demonstrate their usage in the kitchen sink example.
  2. Add a brief comment explaining the purpose of the Chat component in the context of this example.

Example:

{/* Chat component demonstrating real-time communication features */}
<Chat 
  // TODO: Add configuration props if applicable, e.g.:
  // initialMessage="Welcome to the kitchen sink example!"
  // maxMessages={50}
/>

This will enhance the educational value of the kitchen sink example by showcasing how to configure and use the Chat component.


1-39: Summary: Good foundation, but further development needed.

The Home component provides a solid foundation for the kitchen sink example. However, to fully meet the PR objectives and complete the checklist items:

  1. Implement the missing functionality in the settings and stats sections.
  2. Address the unused imports or clarify their intended use.
  3. Consider the performance optimizations and accessibility improvements suggested in previous comments.
  4. Add unit tests for the Home component and its child components.
  5. Update the documentation to explain the purpose and usage of this kitchen sink example.
  6. Ensure that a dedicated CI job is created for testing this new example.

Once these items are addressed, the kitchen sink example will be more comprehensive and align better with the PR objectives.

examples/example-vite-kitchen-sink/src/lib/utils.ts (1)

24-58: LGTM: Comprehensive character mapping

The charMap is well-defined with a comprehensive list of accented characters and their ASCII equivalents. Defining it outside the accentsToAscii function is good for performance.

Minor suggestion: Consider adding a comment explaining the purpose of the single quote mapping ("'": "'"). This might help prevent accidental removal in future updates.

examples/example-vite-kitchen-sink/README.md (1)

37-38: Improve clarity of deployment prerequisites

The current wording can be slightly improved for clarity. Consider this revision:

- In order to make those commands work, you need to have torii & katana running.
+ To execute these commands successfully, ensure that both torii and katana are running.

This change makes the prerequisite clearer and more concise.

🧰 Tools
🪛 LanguageTool

[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)

examples/example-vite-kitchen-sink/src/components/ui/button.tsx (2)

8-35: LGTM: Well-structured button variants with a suggestion

The buttonVariants definition using cva is well-structured and provides a good range of variants and sizes. The use of focus states aligns with accessibility best practices.

Consider adding explicit dark mode support to ensure consistent appearance across different color schemes.

You could add dark mode variants like this:

variants: {
  // ... existing variants
  dark: {
    default: "bg-gray-800 text-white hover:bg-gray-700",
    destructive: "bg-red-800 text-white hover:bg-red-700",
    // ... other dark mode variants
  }
}

Then use it in combination with a dark mode class or media query in your application.


44-60: LGTM: Well-implemented Button component with a minor suggestion

The Button component is well-implemented, using forwardRef for proper ref handling, providing flexibility with the asChild prop, and handling the loading state effectively.

Consider a minor optimization for the disabled state:

Instead of using the nullish coalescing operator, you could use a logical OR for a slightly more concise expression:

disabled={props.disabled || loading}

This change maintains the same functionality while being a bit more idiomatic in JavaScript/TypeScript.

examples/example-vite-kitchen-sink/src/app/globals.css (3)

10-14: Consider adding a browser compatibility note for text-wrap: balance.

The text-balance utility class uses the text-wrap: balance property, which is a modern CSS feature. While it's a great addition for improved text rendering, it's worth noting that it might not be supported in all browsers.

Consider adding a comment above this utility class to indicate its browser support status, or ensure that fallback styles are in place for browsers that don't support this feature.


16-97: Great theming setup with a suggestion for chart colors.

The use of CSS variables for theming is excellent, providing flexibility for light, dark, and custom "dojo" themes. The color palette is well-defined and consistent across themes.

Consider making the chart color variables more generic for better reusability. Instead of --chart-1, --chart-2, etc., you could use names like --chart-primary, --chart-secondary, etc. This would make it easier to use these colors in different contexts without being tied to specific numbering.


100-111: Base styles look good, with a note on heading selectors.

The use of @apply for global styles and setting consistent font families for the body and headings are good practices.

In the heading selector on line 108, h7 is included, which is not a standard HTML heading tag. Consider removing it as it won't have any effect and might confuse other developers:

-  h1, h2, h3, h4, h5, h6, h7 {
+  h1, h2, h3, h4, h5, h6 {
     font-family: var(--font-geist-sans);
   }
examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (2)

16-27: Consider adding error handling to handleCallerClick

The contract write setup looks good, and you've addressed the previous comment about hard-coding contract addresses by using dojoConfig. However, the handleCallerClick function doesn't handle potential errors from incrementCallerCounter. Consider adding error handling to improve robustness.

Here's a suggested improvement:

 const handleCallerClick = useCallback(async () => {
   setIsLoading(true);
-  incrementCallerCounter();
+  try {
+    await incrementCallerCounter();
+  } catch (error) {
+    console.error("Failed to increment counter:", error);
+    // Optionally, show an error message to the user
+  } finally {
+    setIsLoading(false);
+  }
-  setIsLoading(true);
 }, [incrementCallerCounter, setIsLoading]);

This change ensures that loading state is properly managed even if an error occurs, and it provides basic error logging.


29-51: LGTM: Initial data fetching looks good

The initial data fetching logic is well-implemented. It correctly handles cases where no entity is found or the counter is undefined. The use of parseInt with base 16 for parsing hexadecimal values is appropriate.

One minor suggestion: Consider adding more robust error handling in the getEntity function. While logging to console is a good start, you might want to update the component state or show an error message to the user in case of a failure.

Here's a small suggestion for improved error handling:

 if (address && db) {
-  getEntity(db, address).then(setCount).catch(console.error)
+  getEntity(db, address)
+    .then(setCount)
+    .catch(error => {
+      console.error("Failed to fetch initial count:", error);
+      // Optionally, set an error state or show a message to the user
+    });
 }
examples/example-vite-kitchen-sink/src/components/ui/select.tsx (3)

13-31: LGTM: SelectTrigger component is well-implemented with a minor suggestion.

The SelectTrigger component is well-structured, using React.forwardRef and following best practices. The use of cn for className composition allows for easy customization.

Consider adding an aria-haspopup="listbox" attribute to the SelectPrimitive.Trigger for improved accessibility:

 <SelectPrimitive.Trigger
   ref={ref}
   className={cn(
     "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
     className
   )}
+  aria-haspopup="listbox"
   {...props}
 >

68-98: LGTM: SelectContent component is well-implemented with a suggestion for optimization.

The SelectContent component is well-structured, using a Portal for proper rendering and including smooth animations for open/close states. The support for different positioning options adds flexibility.

Consider memoizing the className string to optimize performance, especially if this component is used frequently:

const contentClassName = React.useMemo(
  () => cn(
    "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
    position === "popper" &&
    "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
    className
  ),
  [position, className]
);

// Then use contentClassName in the component

This optimization can help reduce unnecessary re-renders if the component is used in a performance-critical part of your application.


112-133: LGTM: SelectItem component is well-implemented with a suggestion for accessibility.

The SelectItem component is well-structured, using React.forwardRef and providing clear visual feedback for selected items. The use of data attributes for styling different states adds flexibility.

Consider adding an aria-selected attribute to improve accessibility:

 <SelectPrimitive.Item
   ref={ref}
   className={cn(
     "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
     className
   )}
+  aria-selected={props.selected}
   {...props}
 >

This will help screen readers announce whether an item is currently selected.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 00427bc and 6a8d9f0.

⛔ Files ignored due to path filters (5)
  • examples/example-vite-kitchen-sink/public/dojo-logo.svg is excluded by !**/*.svg
  • examples/example-vite-kitchen-sink/src/app/favicon.ico is excluded by !**/*.ico
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistMonoVF.woff is excluded by !**/*.woff
  • examples/example-vite-kitchen-sink/src/app/fonts/GeistVF.woff is excluded by !**/*.woff
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (44)
  • .gitignore (1 hunks)
  • .gitmodules (1 hunks)
  • examples/example-vite-kitchen-sink/.env.dist (1 hunks)
  • examples/example-vite-kitchen-sink/.eslintrc.json (1 hunks)
  • examples/example-vite-kitchen-sink/.gitignore (1 hunks)
  • examples/example-vite-kitchen-sink/README.md (1 hunks)
  • examples/example-vite-kitchen-sink/components.json (1 hunks)
  • examples/example-vite-kitchen-sink/index.html (1 hunks)
  • examples/example-vite-kitchen-sink/netlify.toml (1 hunks)
  • examples/example-vite-kitchen-sink/package.json (1 hunks)
  • examples/example-vite-kitchen-sink/postcss.config.mjs (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/globals.css (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/layout.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/app/page.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/chat.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/header.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/theme-switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/button.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/dropdown.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/select.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/models.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/src/env.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/lib/utils.ts (1 hunks)
  • examples/example-vite-kitchen-sink/src/main.tsx (1 hunks)
  • examples/example-vite-kitchen-sink/tailwind.config.ts (1 hunks)
  • examples/example-vite-kitchen-sink/tsconfig.json (1 hunks)
  • examples/example-vite-kitchen-sink/vite.config.ts (1 hunks)
  • worlds/onchain-dash (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (33)
  • .gitignore
  • .gitmodules
  • examples/example-vite-kitchen-sink/.env.dist
  • examples/example-vite-kitchen-sink/.eslintrc.json
  • examples/example-vite-kitchen-sink/.gitignore
  • examples/example-vite-kitchen-sink/components.json
  • examples/example-vite-kitchen-sink/index.html
  • examples/example-vite-kitchen-sink/netlify.toml
  • examples/example-vite-kitchen-sink/package.json
  • examples/example-vite-kitchen-sink/postcss.config.mjs
  • examples/example-vite-kitchen-sink/src/components/chat.tsx
  • examples/example-vite-kitchen-sink/src/components/global-counter.tsx
  • examples/example-vite-kitchen-sink/src/components/header.tsx
  • examples/example-vite-kitchen-sink/src/components/sidebar.tsx
  • examples/example-vite-kitchen-sink/src/components/starknet-provider.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/badge.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/drawer.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/input.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/label.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/switch.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/textarea.tsx
  • examples/example-vite-kitchen-sink/src/components/ui/tooltip.tsx
  • examples/example-vite-kitchen-sink/src/components/wallet-account.tsx
  • examples/example-vite-kitchen-sink/src/config.ts
  • examples/example-vite-kitchen-sink/src/dojo.config.ts
  • examples/example-vite-kitchen-sink/src/dojo/models.ts
  • examples/example-vite-kitchen-sink/src/dojo/provider.tsx
  • examples/example-vite-kitchen-sink/src/env.ts
  • examples/example-vite-kitchen-sink/src/main.tsx
  • examples/example-vite-kitchen-sink/tailwind.config.ts
  • examples/example-vite-kitchen-sink/tsconfig.json
  • examples/example-vite-kitchen-sink/vite.config.ts
  • worlds/onchain-dash
🧰 Additional context used
🪛 LanguageTool
examples/example-vite-kitchen-sink/README.md

[uncategorized] ~3-~3: You might be missing the article “the” here.
Context: ...n Sink This project aims at showcasing dojo's capabilities outside of gaming. ## G...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)


[uncategorized] ~48-~48: You might be missing the article “the” here.
Context: ... ### Notes - you main want to updateactionscontract address insrc/compon...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

🪛 Biome
examples/example-vite-kitchen-sink/src/app/layout.tsx

[error] 8-8: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

examples/example-vite-kitchen-sink/src/lib/utils.ts

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)

🔇 Additional comments (30)
examples/example-vite-kitchen-sink/src/app/layout.tsx (2)

1-5: LGTM: Imports are well-organized and relevant.

The import statements are logically organized and include all necessary components for the RootLayout. No unused imports are present.


8-8: ⚠️ Potential issue

Simplify the type definition for RootLayout.

As suggested in a previous review, you can simplify the type definition for RootLayout. This change will also address the static analysis hint.

Apply this change:

-export default function RootLayout({ children }: React.PropsWithChildren<{}>) {
+export default function RootLayout({ children }: React.PropsWithChildren) {

This simplification improves type clarity and removes the unnecessary empty object type.

🧰 Tools
🪛 Biome

[error] 8-8: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

examples/example-vite-kitchen-sink/src/app/page.tsx (1)

11-15: Approve layout structure and clarify x-chunk attribute.

The responsive layout structure looks good and aligns with best practices for different screen sizes. However, the purpose of the x-chunk attribute is unclear.

Could you please clarify the intended use of the x-chunk attribute? If it's related to code splitting or lazy loading, consider adding a comment explaining its purpose for better maintainability.

examples/example-vite-kitchen-sink/src/lib/utils.ts (5)

4-6: LGTM: Efficient class name utility function

The cn function is well-implemented, using clsx for combining class values and twMerge for intelligent merging of Tailwind CSS classes. This approach is a best practice for handling dynamic class names in React components with Tailwind.


18-23: LGTM: Efficient transliteration function

The transliterate function is well-implemented:

  • It uses a functional approach with split, map, and join for efficient character mapping.
  • The default empty object for charMap is a good practice, allowing the function to be called without a map if needed.

60-63: LGTM: Optimized accent removal function

The accentsToAscii function is well-implemented and optimized:

  • It uses the transliterate function with the pre-defined charMap.
  • The charMap is defined outside the function, addressing the performance concern mentioned in the past review comment.

Good job on implementing the suggested optimization!


65-68: LGTM: Effective ASCII normalization function

The toValidAscii function is well-implemented:

  • It uses normalize("NFD") to decompose characters, which is the correct approach.
  • The regular expression /[\u0300-\u036f]/g correctly removes combining diacritical marks.

Note: The static analysis tool flagged a "misleading character class" on line 67, but this is a false positive. The character class [\u0300-\u036f] is correct for matching combining diacritical marks in the Unicode range U+0300 to U+036F.

🧰 Tools
🪛 Biome

[error] 67-67: Unexpected combined character in the character class.

(lint/suspicious/noMisleadingCharacterClass)


70-72: LGTM: Concise address shortening function

The shortAddress function is well-implemented:

  • It correctly truncates the address to show the first 6 and last 4 characters.
  • This is a common and user-friendly pattern for displaying blockchain addresses.
  • The implementation is concise and efficient.
examples/example-vite-kitchen-sink/README.md (1)

48-48: ⚠️ Potential issue

Fix typo in the first note

There's a small typo in the first note. Please correct it as follows:

- - you main want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.
+ - you may want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.

This correction ensures clear communication of the potential need to update contract addresses.

Likely invalid or redundant comment.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~48-~48: You might be missing the article “the” here.
Context: ... ### Notes - you main want to updateactionscontract address insrc/compon...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

examples/example-vite-kitchen-sink/src/components/ui/button.tsx (3)

1-6: LGTM: Imports and utility functions are well-organized

The imports are appropriate for the component's functionality, utilizing React, Radix UI, and class-variance-authority. The use of Radix UI's Slot component suggests good composability, and the cva import indicates a clean approach to variant-based styling.


37-42: LGTM: Well-defined ButtonProps interface

The ButtonProps interface is well-structured, extending appropriate types and adding useful custom props. The asChild prop enhances composability, while the loading prop provides a convenient way to handle async operations.


62-62: LGTM: Appropriate exports

Exporting both the Button component and the buttonVariants function is a good practice. This allows for flexible usage of the button styles in other components if needed.

examples/example-vite-kitchen-sink/src/app/globals.css (2)

1-8: LGTM: Tailwind setup and initial styles look good.

The Tailwind directives are correctly implemented, and the use of CSS variables for body styles promotes maintainability and theming flexibility.


1-111: Overall, excellent implementation of global styles and theming.

This globals.css file provides a robust foundation for the kitchen sink example. It effectively utilizes Tailwind CSS, implements a flexible theming system, and follows modern CSS practices. The minor suggestions provided earlier will further enhance its quality and maintainability.

Great job on creating a comprehensive styling solution that aligns well with the PR objective!

examples/example-vite-kitchen-sink/src/components/caller-counter.tsx (2)

1-15: LGTM: Imports and component setup look good

The imports and initial component setup are well-structured. The use of React hooks, Starknet hooks, and custom hooks is appropriate for the component's functionality. The state variables are correctly declared using useState.


91-105: LGTM: Component rendering is well-implemented

The rendering logic for the CallerCounter component is well-structured and follows good practices:

  • The use of a fieldset provides a clear grouping for the counter elements.
  • The count display and button are logically arranged.
  • The Button component correctly uses the loading prop to indicate the operation's progress, which is good for user experience.
  • The class names suggest appropriate styling, likely using a CSS framework like Tailwind.

Overall, this part of the component is well-implemented and provides a clear, user-friendly interface.

examples/example-vite-kitchen-sink/src/components/ui/select.tsx (5)

1-11: LGTM: Imports and basic component definitions are well-structured.

The imports and basic component definitions are appropriate and follow best practices. The use of Radix UI primitives provides a solid foundation for building accessible and customizable select components.


33-66: LGTM: ScrollUpButton and ScrollDownButton components are well-implemented.

The SelectScrollUpButton and SelectScrollDownButton components are consistently structured and follow React best practices. The use of ChevronUp and ChevronDown icons provides clear visual cues for scrolling functionality.


100-110: LGTM: SelectLabel component is well-implemented.

The SelectLabel component follows React best practices and maintains consistent styling with other components in the file. The use of React.forwardRef ensures proper ref handling.


135-145: LGTM: SelectSeparator component is well-implemented.

The SelectSeparator component follows React best practices and provides appropriate styling for a visual separator between items. The use of React.forwardRef ensures proper ref handling.


147-158: LGTM: Exports are comprehensive.

All implemented components are properly exported, providing users of this module with access to the full range of Select components.

examples/example-vite-kitchen-sink/src/components/ui/dialog.tsx (9)

1-6: Imports are well-structured and necessary

All imported modules and utilities are appropriately used within the file. The cn utility function is correctly imported for class name manipulation.


7-13: Primitive components are correctly re-exported

The Dialog primitives (Dialog, DialogTrigger, DialogPortal, DialogClose) are appropriately assigned and ready for use in the component hierarchy.


15-28: DialogOverlay component is properly implemented

The DialogOverlay component correctly uses React.forwardRef to forward refs, and it spreads additional props as expected. The class names are managed using the cn utility, which ensures conditional class application.


30-52: DialogContent component is well-structured with accessibility considerations

The DialogContent component wraps content within DialogPortal and includes DialogOverlay, ensuring proper layering of the dialog. It correctly forwards refs and applies class names for styling and animations. The inclusion of the DialogPrimitive.Close component with an accessible name enhances usability.


54-66: DialogHeader component is neatly defined

The DialogHeader component accepts HTML attributes and applies the appropriate class names for styling. It provides a flexible header section for the dialog.


68-80: DialogFooter component ensures responsive design

The DialogFooter component utilizes flex layouts to adjust content alignment based on screen size, enhancing the dialog's responsiveness.


82-96: DialogTitle component correctly forwards refs and styles

The DialogTitle component uses React.forwardRef and applies semantic HTML elements with appropriate styling, contributing to the dialog's accessibility.


97-107: DialogDescription component enhances accessibility

By providing a styled description component that forwards refs, the DialogDescription promotes better accessibility practices within dialogs.


109-120: Export statements are comprehensive

All components are correctly exported, allowing easy import and usage throughout the project.

Comment on lines +8 to +16
export function ensureStarkFelt(value: string) {
if (!value.startsWith("0x")) {
return value;
}
if (value.length < 66) {
return "0x" + value.replace('0x', '').padStart(64, "0");
}
return value;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve ensureStarkFelt implementation

The current implementation of ensureStarkFelt still has some potential issues:

  1. There's no validation to ensure the input is a valid hexadecimal string.
  2. Inputs longer than 66 characters are not handled explicitly.
  3. The behavior for inputs not starting with "0x" might be unexpected.

Consider implementing the following improvements:

  1. Validate that the input is a valid hexadecimal string.
  2. Handle inputs longer than 66 characters (e.g., truncate or throw an error).
  3. Clarify the intended behavior for inputs not starting with "0x".

Here's a suggested implementation addressing these issues:

export function ensureStarkFelt(value: string): string {
  const hexRegex = /^(0x)?[0-9A-Fa-f]+$/;
  
  if (!hexRegex.test(value)) {
    throw new Error("Invalid input: not a hexadecimal string");
  }

  if (!value.startsWith("0x")) {
    value = "0x" + value;
  }

  const hexPart = value.slice(2);
  if (hexPart.length > 64) {
    throw new Error("Input exceeds maximum length for a Stark felt");
  }

  return "0x" + hexPart.padStart(64, "0");
}

This implementation ensures that:

  1. The input is a valid hexadecimal string.
  2. The "0x" prefix is always added.
  3. The result is always 66 characters long (including "0x").
  4. Inputs that would result in a value longer than 66 characters are rejected.

Please review and adjust based on the specific requirements of Stark felt in your project.

Comment on lines +1 to +3
# OnChainDash Vite Kitchen Sink

This project aims at showcasing dojo's capabilities outside of gaming.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance the introduction with more context and explanation

The introduction provides a basic overview, but it could be more informative. Consider the following improvements:

  1. Add a brief explanation of what dojo.js is for context.
  2. Clarify what a "kitchen sink" example means in this context.
  3. Fix the minor grammatical issue in line 3.

Here's a suggested revision:

# OnChainDash Vite Kitchen Sink

This project serves as a comprehensive "kitchen sink" example, showcasing the full range of dojo.js capabilities outside of gaming. Dojo.js is a powerful framework for building onchain applications and games.

The project aims to demonstrate dojo's versatility by implementing various features and use cases in a non-gaming context.

This enhancement provides more context and clarity for users unfamiliar with dojo.js or the concept of a kitchen sink example.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~3-~3: You might be missing the article “the” here.
Context: ...n Sink This project aims at showcasing dojo's capabilities outside of gaming. ## G...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

Comment on lines +16 to +17
katana --disable-fee --allowed-origins "*"
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve flexibility of katana and torii commands

The current katana and torii commands use hardcoded values, which might not be suitable for all users. Consider making these commands more flexible:

  1. For the katana command, add an option to specify the network:
katana --disable-fee --allowed-origins "*" [--network <network_name>]
  1. For the torii commands, use environment variables or command-line arguments for the world address:
# with katana
torii --world $WORLD_ADDRESS --allowed-origins "*"

# with mainnet|sepolia
torii --world $WORLD_ADDRESS --allowed-origins "*" --rpc $RPC_URL -s $STARTING_BLOCK

These changes allow users to easily customize the commands for their specific setup without modifying the README.

Also applies to: 22-25

### Notes

- you main want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.
- if you want to have braavos & argent wallet working, you need to deploy classes and deploy your wallet manually.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Expand on wallet compatibility note

The note about wallet compatibility could be more informative. Consider expanding it as follows:

- For compatibility with Braavos and Argent wallets, you need to manually deploy wallet classes. This involves:
  1. Deploying the necessary smart contract classes for these wallets.
  2. Manually creating and deploying your wallet using these classes.
  3. Ensuring your dApp is configured to work with these custom wallet deployments.

  Refer to the documentation of respective wallets for detailed instructions on this process.

This expansion provides users with a clearer understanding of what's required for wallet compatibility and points them towards finding more detailed instructions.

Comment on lines +1 to +49
# OnChainDash Vite Kitchen Sink

This project aims at showcasing dojo's capabilities outside of gaming.

## Getting Started

First, install dependencies:

```bash
pnpm install
```

In one terminal window, start katana (the sequencer). If you want to use sepolia / mainnet contracts, you can just use a classic rpc (e.g. `https://rpc.netermind.io/(mainnet|sepolia)-juno`). If this is the case, you can skip the next command.

```bash
katana --disable-fee --allowed-origins "*"
```

In another terminal window, start torii server

```bash
# with katana
torii --world 0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12 --allowed-origins "*"
# with mainnet|sepolia
torii --world 0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12 --allowed-origins "*" --rpc "https://rpc.nethermind.io/(mainnet|sepolia)-juno?apikey={apikey}" -s 204922
```

Then, start the development server:

```bash
pnpm run dev
```

Open [http://localhost:5173](http://localhost:5173) with your browser to see the result.

## Local Contracts deployment

In order to make those commands work, you need to have torii & katana running.

```bash
cd src/onchain
sozo build
sozo migrate apply
```

### Notes

- you main want to update `actions` contract address in `src/components/caller-counter.tsx` & `src/components/global-counter.tsx` which is hardcoded in those files.
- if you want to have braavos & argent wallet working, you need to deploy classes and deploy your wallet manually.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance README with additional sections

While the current README provides essential setup and deployment instructions, consider adding the following sections to make it more comprehensive:

  1. Project Structure: Provide an overview of the project's directory structure and main components.

  2. Features Demonstrated: List and briefly explain the dojo.js features showcased in this kitchen sink example.

  3. Configuration: If there are any configuration options or environment variables, document them here.

  4. Troubleshooting: Add a section with common issues and their solutions.

  5. Contributing: Include guidelines for how others can contribute to this example project.

  6. License: Specify the license under which this example is released.

These additions would significantly enhance the README, making it more informative and user-friendly. Would you like assistance in drafting content for these sections?

🧰 Tools
🪛 LanguageTool

[uncategorized] ~3-~3: You might be missing the article “the” here.
Context: ...n Sink This project aims at showcasing dojo's capabilities outside of gaming. ## G...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[style] ~37-~37: Consider a shorter alternative to avoid wordiness.
Context: ...result. ## Local Contracts deployment In order to make those commands work, you need to h...

(IN_ORDER_TO_PREMIUM)


[uncategorized] ~48-~48: You might be missing the article “the” here.
Context: ... ### Notes - you main want to updateactionscontract address insrc/compon...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

Comment on lines +53 to +90
useEffect(() => {
async function subscribeToEntityUpdates(db: SDK<OnchainDashSchemaType>, address: string) {
const sub = await db.subscribeEntityQuery({
// @ts-expect-error $eq is working there
onchain_dash: { CallerCounter: { $: { where: { caller: { $eq: ensureStarkFelt(address) } } } } }
}, ({ data, error }) => {
if (data) {
const entity = data.pop();
if (!entity) {
return;
}
if (entity.models.onchain_dash?.CallerCounter?.counter === undefined) {
return
}
const count = entity.models.onchain_dash?.CallerCounter?.counter;
if (undefined === count) {
return 0;
}

setIsLoading(false);
setCount(parseInt(count.toString(), 16));
return;
}
if (error) {
throw error;
}
});
setSub(sub);
}
if (address && db && sub === null) {
subscribeToEntityUpdates(db, address).then(() => { }).catch(console.error)
}
return () => {
if (sub) {
sub.free();
}
};
}, [address, db, sub]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize useEffect dependencies

The current implementation includes sub in the dependency array, which may cause unnecessary re-subscriptions when sub changes. Additionally, the cleanup function might not correctly reference the sub value at the time of unmounting.

Consider the following optimization:

- useEffect(() => {
+ useEffect(() => {
+  let currentSub: Subscription | null = null;
   async function subscribeToEntityUpdates(db: SDK<OnchainDashSchemaType>, address: string) {
     const sub = await db.subscribeEntityQuery({
       // ... (subscription logic)
     });
-    setSub(sub);
+    currentSub = sub;
   }
   if (address && db && sub === null) {
     subscribeToEntityUpdates(db, address).then(() => { }).catch(console.error)
   }
   return () => {
-    if (sub) {
-      sub.free();
+    if (currentSub) {
+      currentSub.free();
     }
   };
- }, [address, db, sub]);
+ }, [address, db]);

This change ensures that the effect doesn't re-run unnecessarily and that the cleanup function always has access to the current subscription.

📝 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
useEffect(() => {
async function subscribeToEntityUpdates(db: SDK<OnchainDashSchemaType>, address: string) {
const sub = await db.subscribeEntityQuery({
// @ts-expect-error $eq is working there
onchain_dash: { CallerCounter: { $: { where: { caller: { $eq: ensureStarkFelt(address) } } } } }
}, ({ data, error }) => {
if (data) {
const entity = data.pop();
if (!entity) {
return;
}
if (entity.models.onchain_dash?.CallerCounter?.counter === undefined) {
return
}
const count = entity.models.onchain_dash?.CallerCounter?.counter;
if (undefined === count) {
return 0;
}
setIsLoading(false);
setCount(parseInt(count.toString(), 16));
return;
}
if (error) {
throw error;
}
});
setSub(sub);
}
if (address && db && sub === null) {
subscribeToEntityUpdates(db, address).then(() => { }).catch(console.error)
}
return () => {
if (sub) {
sub.free();
}
};
}, [address, db, sub]);
useEffect(() => {
let currentSub: Subscription | null = null;
async function subscribeToEntityUpdates(db: SDK<OnchainDashSchemaType>, address: string) {
const sub = await db.subscribeEntityQuery({
// @ts-expect-error $eq is working there
onchain_dash: { CallerCounter: { $: { where: { caller: { $eq: ensureStarkFelt(address) } } } } }
}, ({ data, error }) => {
if (data) {
const entity = data.pop();
if (!entity) {
return;
}
if (entity.models.onchain_dash?.CallerCounter?.counter === undefined) {
return
}
const count = entity.models.onchain_dash?.CallerCounter?.counter;
if (undefined === count) {
return 0;
}
setIsLoading(false);
setCount(parseInt(count.toString(), 16));
return;
}
if (error) {
throw error;
}
});
currentSub = sub;
}
if (address && db && sub === null) {
subscribeToEntityUpdates(db, address).then(() => { }).catch(console.error)
}
return () => {
if (currentSub) {
currentSub.free();
}
};
}, [address, db]);

Comment on lines +1 to +158
)}
{...props}
>
<ChevronDown className="h-4 w-4" />
</SelectPrimitive.ScrollDownButton>
))
SelectScrollDownButton.displayName =
SelectPrimitive.ScrollDownButton.displayName

const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
))
SelectContent.displayName = SelectPrimitive.Content.displayName

const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
{...props}
/>
))
SelectLabel.displayName = SelectPrimitive.Label.displayName

const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>

<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))
SelectItem.displayName = SelectPrimitive.Item.displayName

const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName

export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Incomplete PR Objectives: Missing Documentation, Tests, and CI Job

The verification script revealed the following issues:

  • Documentation Missing: No documentation found for Select components. Please update the documentation to include these new components.
  • Unit Tests Missing: No test files found for Select components. Please add comprehensive unit tests to ensure functionality and reliability.
  • CI Job Missing: No CI job found for kitchen sink examples. Consider adding a dedicated CI job to automatically test these examples.
  • Pending TODOs/FIXMEs: Existing TODOs and FIXMEs in the codebase need to be addressed to maintain code quality.
🔗 Analysis chain

Overall: Excellent implementation of select components with minor suggestions for improvement.

This file provides a comprehensive set of select components built on Radix UI primitives, offering a solid foundation for a customizable and accessible select dropdown. The implementation follows React best practices, maintains consistency across components, and provides appropriate styling for various states and interactions.

Addressing the PR objectives:

  1. The implementation successfully adds a kitchen sink example for select components, enhancing the dojo.js project.
  2. The code demonstrates good quality and adherence to best practices.

To fully complete the PR objectives:

  1. Ensure that documentation is updated to reflect these new components.
  2. Add unit tests to verify the functionality of these components.
  3. Consider creating a dedicated CI job for testing these new examples.
  4. Complete a self-review of the code, addressing any remaining TODOs or FIXMEs.

The minor suggestions for accessibility improvements (adding aria-haspopup and aria-selected attributes) will further enhance the overall quality of the implementation.

To verify the completion of the PR objectives, you can run the following script:

This script will help verify the completion of the remaining PR objectives and highlight any areas that need attention.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for documentation updates
echo "Checking for documentation updates..."
grep -r "Select" docs/ || echo "No documentation found for Select components. Please update the documentation."

# Check for test files
echo "Checking for test files..."
find . -name "*select*.test.*" || echo "No test files found for Select components. Please add unit tests."

# Check for CI job
echo "Checking for CI job..."
grep "kitchen-sink" .github/workflows/*.yml || echo "No CI job found for kitchen sink examples. Consider adding a dedicated CI job."

# Check for TODOs and FIXMEs
echo "Checking for TODOs and FIXMEs..."
grep -r "TODO\|FIXME" . || echo "No TODOs or FIXMEs found."

Length of output: 1176

Comment on lines +37 to +46
const handleChangeTheme = useCallback(async (theme: AvailableTheme) => {
setIsLoading(true);
await writeAsync({
calls: [{
contractAddress: dojoConfig.manifest.contracts[0].address,
entrypoint: "change_theme",
calldata: [theme]
}]
})
}, [writeAsync]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure isLoading state is reset and errors are handled in handleChangeTheme

Currently, setIsLoading(true) is called at the beginning of handleChangeTheme, but setIsLoading(false) is only set after the subscription receives an update (line 91). If there's an error or delay in the writeAsync call or the subscription fails, isLoading may remain true, causing the button to stay in the loading state indefinitely.

Consider adding error handling within handleChangeTheme and resetting isLoading in a finally block to ensure it is always reset regardless of success or failure.

Apply this diff to handle errors and ensure isLoading is reset:

 const handleChangeTheme = useCallback(async (theme: AvailableTheme) => {
   setIsLoading(true);
+  try {
     await writeAsync({
       calls: [{
         contractAddress: dojoConfig.manifest.contracts[0].address,
         entrypoint: "change_theme",
         calldata: [theme]
       }]
     });
+  } catch (error) {
+    console.error("Error changing theme:", error);
+  } finally {
+    setIsLoading(false);
+  }
 }, [writeAsync]);
📝 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 handleChangeTheme = useCallback(async (theme: AvailableTheme) => {
setIsLoading(true);
await writeAsync({
calls: [{
contractAddress: dojoConfig.manifest.contracts[0].address,
entrypoint: "change_theme",
calldata: [theme]
}]
})
}, [writeAsync]);
const handleChangeTheme = useCallback(async (theme: AvailableTheme) => {
setIsLoading(true);
try {
await writeAsync({
calls: [{
contractAddress: dojoConfig.manifest.contracts[0].address,
entrypoint: "change_theme",
calldata: [theme]
}]
});
} catch (error) {
console.error("Error changing theme:", error);
} finally {
setIsLoading(false);
}
}, [writeAsync]);

Comment on lines +25 to +45
const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean
}
>(({ className, inset, children, ...props }, ref) => (
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
inset && "pl-8",
className
)}
{...props}
>
{children}
<ChevronRightIcon className="ml-auto h-4 w-4" />
</DropdownMenuPrimitive.SubTrigger>
))
DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider RTL Support for Submenu Icon Direction

Currently, the DropdownMenuSubTrigger component uses ChevronRightIcon to indicate submenus opening to the right. For right-to-left (RTL) language support, consider adjusting the icon direction or conditionally rendering the icon based on the user's locale to enhance usability in RTL layouts.

Comment on lines +88 to +96
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
inset && "pl-8",
className
)}
{...props}
/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor to Reduce Code Duplication

The DropdownMenuItem, DropdownMenuCheckboxItem, and DropdownMenuRadioItem components share similar structures and styling in their className and layout. Refactoring these components to extend a common base component can reduce code duplication and improve maintainability.

For example, you can create a base component:

const DropdownMenuItemBase = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
    inset?: boolean;
  }
>(({ className, inset, children, ...props }, ref) => (
  <DropdownMenuPrimitive.Item
    ref={ref}
    className={cn(
      "relative flex cursor-default select-none items-center rounded-sm py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
      inset ? "pl-8 pr-2" : "px-2 py-1.5",
      className
    )}
    {...props}
  >
    {children}
  </DropdownMenuPrimitive.Item>
));
DropdownMenuItemBase.displayName = "DropdownMenuItemBase";

Then, refactor the specific components:

-const DropdownMenuItem = React.forwardRef<...>
-  // existing code
-)
+const DropdownMenuItem = DropdownMenuItemBase;

-const DropdownMenuCheckboxItem = React.forwardRef<...>
-  // existing code
-)
+const DropdownMenuCheckboxItem = React.forwardRef<
+  React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
+  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
+>(({ children, checked, ...props }, ref) => (
+  <DropdownMenuPrimitive.CheckboxItem ref={ref} checked={checked} {...props}>
+    <DropdownMenuItemBase inset>
+      <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
+        <DropdownMenuPrimitive.ItemIndicator>
+          <CheckIcon className="h-4 w-4" />
+        </DropdownMenuPrimitive.ItemIndicator>
+      </span>
+      {children}
+    </DropdownMenuItemBase>
+  </DropdownMenuPrimitive.CheckboxItem>
+));

-const DropdownMenuRadioItem = React.forwardRef<...>
-  // existing code
-)
+const DropdownMenuRadioItem = React.forwardRef<
+  React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
+  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
+>(({ children, ...props }, ref) => (
+  <DropdownMenuPrimitive.RadioItem ref={ref} {...props}>
+    <DropdownMenuItemBase inset>
+      <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
+        <DropdownMenuPrimitive.ItemIndicator>
+          <DotFilledIcon className="h-4 w-4 fill-current" />
+        </DropdownMenuPrimitive.ItemIndicator>
+      </span>
+      {children}
+    </DropdownMenuItemBase>
+  </DropdownMenuPrimitive.RadioItem>
+));

Also applies to: 104-120, 128-143

@ponderingdemocritus ponderingdemocritus merged commit 06a2372 into main Oct 3, 2024
3 checks passed
@ponderingdemocritus ponderingdemocritus deleted the feat/example-sink branch October 3, 2024 07:59
@MartianGreed MartianGreed restored the feat/example-sink branch October 3, 2024 15:48
This was referenced Oct 3, 2024
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.

2 participants