-
Notifications
You must be signed in to change notification settings - Fork 45
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
Conversation
WalkthroughThe 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 Changes
Possibly related PRs
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
0be3783
to
f4bd1d7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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 neededThe 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 automaticallypostcss-preset-env
for using future CSS featurescssnano
for minifying CSS in productionIf 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 thecreateDojoConfig
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:
- Add comments explaining the purpose of each part of the configuration and how it can be customized.
- Include examples of additional configuration options that might be useful in different scenarios.
- Consider adding error handling or validation for the manifest import.
- 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 configurationThank you for adding this configuration file. Here are some overall suggestions to improve it:
- Consistency: Ensure all URLs are appropriate for the intended environment (development, staging, or production).
- Security:
- Implement proper API key management.
- Use HTTPS for all non-localhost URLs in production.
- Clarity: Clarify the distinction between
VITE_CONTROLLER_URL
andVITE_CONTROLLER_RPC
if they serve different purposes.- 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 withRootLayout
wrappingHome
is good for separation of concerns.However, the use of the non-null assertion operator (
!
) ongetElementById("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:
- A file-level comment explaining the purpose of this utility file.
- JSDoc comments for each function, describing their purpose, parameters, and return values.
- 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:
- Add a meta description tag for better SEO.
- Update the title to be more specific to the kitchen sink example.
- 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:
- Verify the CSS file path and Vite compatibility for aliases as mentioned in previous comments.
- Consider adding a prefix to Tailwind classes to avoid potential conflicts.
- Update project documentation to reflect the use of this new example.
Additionally, to complete the kitchen sink example:
- Implement the actual components and pages that demonstrate various Shadcn UI features.
- Add necessary Vite configuration files.
- Create a README.md file for this example, explaining its purpose and how to run it.
- Add tests for the example components.
- 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 ofzod
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 inshortAddress
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 returningundefined
. 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
: Addtype="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 theButton
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 optionsThe 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:
- Add a "target" option to specify the ECMAScript target version (e.g., "es2020" or "esnext").
- 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' sectionThe 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:
- External libraries (e.g., React if needed)
- UI components
- Custom components
- 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:
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.
Sidebar Width: The fixed left padding (
pl-[53px]
) suggests a fixed sidebar width. Consider making this responsive or using CSS variables for better maintainability.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 withcva
. Consider adding documentation.The
labelVariants
function usescva
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 usingReact.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:
- Tests: Add unit tests for this component to ensure its functionality.
- Documentation: Update or create documentation explaining how to use this component.
- CI Job: Create a dedicated CI job for the new examples, including this component.
Consider creating a
README.md
file in theexample-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 theOnchainDashSchemaType
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:
- The purpose and usage of these counters are well-documented in the broader context of the example.
- Any components or services that interact with this schema are consistent with the defined structure.
- 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 usingforwardRef
, correctly handles props, and uses thecn
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 makingautoConnect
configurable.The
StarknetConfig
setup is appropriate for a mainnet configuration, and the use of environment variables for theCartridgeConnector
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:
- Add unit tests to ensure the component behaves correctly under different scenarios.
- Include inline documentation or JSDoc comments to explain the purpose and usage of each exported component.
- 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
oraria-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 typeSDK<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, usinguseEffect
for async initialization and properly providing the context to its children. However, there are a few points to consider:
The world address is hardcoded. Consider moving this to an environment variable for better flexibility across different environments.
Error handling could be improved. Currently, errors are only logged to the console.
Move the world address to an environment variable:
-worldAddress: "0x6dd367f5e11f11e0502cb2c4db7ae9bb6d8b5a4a431750bed7bec88b218e12", +worldAddress: env.VITE_WORLD_ADDRESS,
- 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:
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.Consider using more specific versions for dependencies instead of
^
to ensure consistent builds. For example:- "react": "^18", + "react": "18.2.0",
- Ensure that all workspace dependencies are actually needed in this example:
"@dojoengine/core": "workspace:*", "@dojoengine/sdk": "workspace:*",
- 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:
- Remove
eslint-config-next
if you're not using Next.js in this example:- "eslint-config-next": "14.2.12",
- 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
Consider adding
@typescript-eslint/eslint-plugin
and@typescript-eslint/parser
for better TypeScript linting support.Review if all Vite plugins are necessary for this example. Remove any that are not actively used.
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:
- The project name could be more descriptive.
- Some dependencies and devDependencies may not be necessary for this example.
- 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 usescva
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 theasChild
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 thecn
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:
- The component adds a comprehensive "kitchen sink" example for buttons, which aligns with the PR's main goal.
- The implementation includes various button variants and sizes, providing a good showcase of possibilities.
However, to fully meet the PR objectives:
- Ensure that documentation is updated to include usage examples of this new Button component.
- Add unit tests to verify the component's behavior under different prop combinations.
- Consider creating a dedicated CI job for this new example, as mentioned in the PR checklist.
- 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:
- Ensure consistency with other UI components in terms of styling approach and prop patterns.
- If not already done, consider creating a storybook or similar documentation tool to showcase the various button states and variants.
- 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:
- The kitchen sink example has been successfully added with this Drawer component.
- The code demonstrates good quality and follows best practices.
However, to fully meet the PR objectives:
- Ensure that documentation is updated to include usage examples of this new Drawer component.
- Add unit tests for the Drawer component and its subcomponents.
- Create a dedicated CI job for this new example, if not already done.
- 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:
- 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 )
- 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 colonThere is an extra space before the colon in
Count : {count}
. For consistency and proper formatting, it should beCount: {count}
.Apply this diff:
- Count : {count} + Count: {count}
88-88
: Remove space before the exclamation markThere is an unnecessary space before the exclamation mark in the button text
Click me !
. It should beClick 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 functionThe
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 colonThere 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 textThe 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
⛔ 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 configThe 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 syntaxThe 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 exampleThis 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:
- Consider using environment-specific .env files (e.g., .env.development, .env.production) to manage different configurations.
- Implement a secret management system for handling sensitive data like API keys.
- 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:
- Using environment-specific URLs (e.g., local, staging, production).
- Implementing environment-specific .env files to manage different configurations.
- 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 asVITE_CONTROLLER_URL
.Please clarify:
- Are these variables intended to have the same value?
- If not, what should be the correct value for
VITE_CONTROLLER_RPC
?- 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:
Expand this example to showcase more features of dojo.js, making it a true "kitchen sink" demonstration.
Update the documentation to explain the purpose and features of this kitchen sink example.
Add tests for the components and functionality demonstrated in this example.
Create a dedicated CI job for this new example, as mentioned in the PR checklist.
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 andcn
function look good.The import statements and the
cn
function are well-implemented. The function effectively combinesclsx
for class name concatenation andtwMerge
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." fiexamples/example-vite-kitchen-sink/.gitignore (1)
10-10
: LGTM: Testing and debugging ignore patternsThe 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" andz
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:
- Adding error handling or default values for environment variables.
- 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:
- The example is well-documented, explaining the purpose of each environment variable.
- There's a sample
.env
file or documentation on how to set up these environment variables for users trying out the example.- 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 suggestionImprove 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:
- Use template literals for better readability.
- Use URL constructor for proper URL handling and encoding.
- 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 typescriptLength 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 withinheader.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-sinkLength 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-sinkLength 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-sinkLength 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 neededThe
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:
- Adding 'target' and 'baseUrl' compiler options
- Fixing a syntax error in the 'include' section
- Considering expansion of the 'exclude' section
As this is part of a new kitchen sink example for the dojo.js project, please ensure that:
- The example demonstrates key features of dojo.js
- Documentation is updated to reference this new example
- Any necessary tests are added
- 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:
- Proper use of providers to ensure context availability.
- Clear and logical layout structure.
- Separation of concerns with separate components for Sidebar and Header.
Suggestions for improvement:
- Add TypeScript types for better type safety.
- Enhance responsive design capabilities.
- Consider accessibility improvements.
- 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 inexamples/example-vite-kitchen-sink/src/main.tsx
, ensuring it is correctly integrated into the application.
- Import Statement:
import RootLayout from "./app/layout";
inmain.tsx
- Component Usage:
<RootLayout>
is used withinmain.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:
- Add tests for this new component.
- Update relevant documentation.
- Create a dedicated CI job for the new examples.
- 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 theOnchainDashSchemaType
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 extendsSchemaType
and provides a logical structure for grouping related counters under theonchain_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:
- Documentation: Consider adding JSDoc comments to describe the component's purpose and usage.
- Tests: Add unit tests to ensure the component behaves as expected under various scenarios.
- CI Job: Ensure that this new example is included in the CI pipeline for the project.
To improve the overall architecture:
- Consider creating a
constants.ts
file to store shared CSS classes, making it easier to maintain consistent styling across components.- If not already present, create an
index.ts
file in thecomponents/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 incomponents/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/srcLength 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/srcLength 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/srcLength 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:
- Group imports for better readability.
- Optimize performance by moving provider and connector setup outside the component.
- 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 inexamples/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-sinkLength 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-sinkLength 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 usingcva
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 additionalclassName
props. The use of thecn
utility function for merging class names is a good practice.
1-4
: Verify thecn
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:
- The component contributes to the kitchen sink example as intended.
- Consider updating the PR description to mention this new Switch component specifically.
- Ensure that appropriate tests are added for this component.
- Update any relevant documentation to include information about this new Switch component.
- 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 exampleThe 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:
- Any prerequisite setup for dojo.js
- The correct command to run the kitchen sink example
- The correct URL to view the example (if different from http://localhost:3000)
- 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 thebuttonVariants
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 thattext-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 anduseForm
for form management are good practices. TheuseDojoDb
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:
- Consistent use of the
cn
utility for flexible class name management.- Proper implementation of accessibility features.
- Effective use of React.forwardRef for component composition.
- Comprehensive animations and styling for a polished user experience.
Main suggestions for improvement:
- Consider breaking down long className strings for improved readability, especially in the DialogOverlay and DialogContent components.
- 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 correctThe components
Select
,SelectGroup
, andSelectValue
are correctly assigned fromSelectPrimitive
.
13-31
:SelectTrigger
component is well-implementedThe
SelectTrigger
component correctly utilizesReact.forwardRef
to forward refs. It merges class names using thecn
utility function and properly handles props and children. The inclusion of theChevronDown
icon enhances the user interface.
33-49
:SelectScrollUpButton
component is correctly implementedThe
SelectScrollUpButton
component correctly forwards refs and spreads additional props. It uses thecn
utility to combine class names and includes theChevronUp
icon for user interaction.
50-67
:SelectScrollDownButton
component is correctly implementedThe
SelectScrollDownButton
component mirrors the implementation ofSelectScrollUpButton
, correctly handling refs, props, and class names. It includes theChevronDown
icon, providing intuitive scrolling cues to the user.
68-98
:SelectContent
component is well-structuredThe
SelectContent
component effectively handles theposition
prop with a default of"popper"
and conditionally applies class names based on its value. It correctly integratesSelectScrollUpButton
,SelectViewport
, andSelectScrollDownButton
to manage the dropdown content and scrolling functionality.
100-110
:SelectLabel
component is correctly implementedThe
SelectLabel
component properly forwards refs and spreads props. It utilizes thecn
utility for class names, ensuring consistent styling.
112-133
:SelectItem
component is well-implementedThe
SelectItem
component correctly handles refs and props, and it integrates theSelectPrimitive.ItemIndicator
with theCheck
icon to indicate selected items. The structure ensures accessibility and usability within the dropdown.
135-145
:SelectSeparator
component is correctly implementedThe
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 comprehensiveAll 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 ofDialogDescription
for modal contentYou 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 adiv
or a dedicated content component provided by the library.
{ | ||
"extends": ["next/core-web-vitals", "next/typescript"] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
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:
-
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.
- Use
-
Add custom rules or overrides that are specific to your kitchen sink example.
-
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
path = examples/example-vite-kitchen-sink/src/onchain | ||
url = https://github.com/MartianGreed/onchain-dash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 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:
-
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.
-
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.
-
Remember to update the project documentation to reflect this new submodule and its purpose within the kitchen sink example.
-
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
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 > | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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:
-
Add comments explaining the purpose of each import and component. This will help developers understand the structure and purpose of the example.
-
Consider implementing an error boundary to demonstrate error handling in React applications.
-
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");
}
<!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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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:
- Add comments explaining the purpose of each section and how it relates to the dojo.js project.
- Include placeholder elements or components that demonstrate various features of dojo.js.
- Consider adding CSS links or inline styles to showcase styling capabilities.
- 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.
"tailwind": { | ||
"config": "tailwind.config.ts", | ||
"css": "app/globals.css", | ||
"baseColor": "zinc", | ||
"cssVariables": true, | ||
"prefix": "" | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 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:
-
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.
-
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
<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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
<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> |
<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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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 theTooltipTrigger
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>
<img | ||
src={ | ||
connector.icon.dark | ||
} | ||
className="size-5" | ||
alt={`${connector.name}`} | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
} catch (error) { | ||
setModalOpen(true); | ||
setModalEnabled(true); | ||
console.error(error); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
aria-label="Help" | |
aria-label="Account" |
f4bd1d7
to
54516e5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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 removalThe
accentsToAscii
function provides a solid implementation for removing accents from characters. It covers a wide range of common accented characters and effectively uses thetransliterate
function.Suggestions for minor improvements:
- 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); }
- If a more comprehensive character set is needed, consider using a library like
unidecode
ordiacritics
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
⛔ 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 thechildren
prop. Thedb
state is correctly initialized usinguseState
.
40-45
: LGTM: Provider component's return statement is correct.The
DojoProvider
component correctly wraps its children with theDojoContext.Provider
, passing thedb
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 handlingThe
cn
function effectively combines the power ofclsx
for conditional class names andtwMerge
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 transliterationThe
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 conversionThe
toValidAscii
function provides a robust approach to converting strings to valid ASCII:
- It uses
normalize("NFD")
to decompose characters into their base form and combining characters.- The regex
/[\u0300-\u036f]/g
effectively removes combining diacritical marks.- 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
anduseState
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 neededor
<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 issueConsider 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:
Error handling: The current implementation only logs errors to the console. Consider adding user-facing error messages or notifications.
Message publishing: The code for publishing the message to the database is commented out. Ensure this functionality is implemented before considering the feature complete.
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:
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]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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:
- Create an error state to capture initialization errors.
- Display an error message to the user if initialization fails.
- 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.
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 > | |
) | |
} |
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]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Optimize useEffect and subscription logic.
The existing comment about updating the dependency array is still valid. Additionally, consider these optimizations:
- Move
getEntities
outside ofuseEffect
and memoize it withuseCallback
. - Use
useRef
for the subscription to avoid unnecessary re-renders. - 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.
54516e5
to
e699b8a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (1)
examples/example-vite-kitchen-sink/src/lib/utils.ts (1)
25-63
: LGTM: Comprehensive accent removal implementationThe
accentsToAscii
function provides a thorough mapping of accented characters to their ASCII equivalents. The implementation is clear and makes good use of thetransliterate
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
⛔ 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 theDojoContext.Provider
, passing thedb
value. This follows the React context provider pattern and allows child components to access the Dojo database instance.
12-14
:⚠️ Potential issueReplace 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 suggestionEnhance 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:
- Create an error state to capture initialization errors.
- Display an error message to the user if initialization fails.
- 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 implementationThe
cn
function effectively combines the power ofclsx
for class name concatenation andtwMerge
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 implementationThe
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 improvementsOverall, 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:
- The
cn
function effectively combinesclsx
andtwMerge
for Tailwind CSS class management.- The
ensureStarkFelt
function could benefit from improved input validation and error handling.- The string normalization functions (
transliterate
,accentsToAscii
, andtoValidAscii
) 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 implementationThe
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)
e699b8a
to
a8ca98a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Outside diff range and nitpick comments (6)
examples/example-vite-kitchen-sink/README.md (2)
25-25
: Consider adding a note about API key acquisitionThe 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 updatesThe notes section mentions important manual updates that users might need to perform. To improve clarity and user experience, consider expanding on these points:
- Explain why and when users might need to update the
actions
contract address.- 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 update
actionscontract address in
src/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 usesDate.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
⛔ 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 update
actionscontract address in
src/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 withSDK<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:
- Create an error state to capture initialization errors.
- Display an error message to the user if initialization fails.
- 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:
- Replace the empty
DojoProviderProps
interface with a type alias for better code clarity.- 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 handlingThe
cn
function effectively combines the power ofclsx
for conditional class names andtwMerge
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 transliterationThe
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 normalizationThe
toValidAscii
function effectively normalizes strings by removing accents and diacritical marks. The approach using NFD normalization followed by regex replacement andaccentsToAscii
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 introductionThe 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 guideThe 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 deploymentThe 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
- 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 update
actionscontract address in
src/compon...(AI_EN_LECTOR_MISSING_DETERMINER_THE)
console.log("publish", res) | ||
} catch (error) { | ||
console.error("failed to publish message:", error); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.");
}
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]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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))}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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>
);
28a99b2
to
b65118b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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
, andTheme
interfaces are well-defined and consistent. The use offieldOrder
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
andglobal_counter_key
.
22-32
: LGTM: Enum and constant are well-defined. Consider using string keys in AvailableThemeClassMap.The
AvailableTheme
enum andAvailableThemeClassMap
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 extendsSchemaType
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 theGlobalCounter
,CallerCounter
, andTheme
with default values consistent with their interfaces.Consider the following improvements:
- Abstract magic numbers into named constants for better readability and maintainability:
const DEFAULT_GLOBAL_COUNTER_KEY = 9999999; const DEFAULT_THEME_KEY = 9999999;- Add comments explaining the significance of these default values, especially for
global_counter_key
andtheme_key
.- 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:
- Add comprehensive JSDoc comments to explain the purpose and usage of each interface, enum, and constant.
- Consider creating a separate types file if this schema is used across multiple components.
- Implement unit tests to ensure the schema behaves as expected, especially if you introduce factory functions as suggested earlier.
- 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 sentenceThe 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
⛔ 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 combinationThe
cn
function effectively combines class values usingclsx
andtwMerge
. This approach is a best practice for managing Tailwind CSS classes, ensuring proper merging and conflict resolution.
18-23
: LGTM: Efficient character transliterationThe
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 normalizationThe
toValidAscii
function effectively normalizes strings by removing accents and diacritics. The approach of usingnormalize("NFD")
followed by regex replacement andaccentsToAscii
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 introductionThe 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" sectionThe "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 deploymentThe "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 notesThe "Notes" section provides useful additional information for users, including details about updating contract addresses and wallet compatibility.
48-48
: Fix typo in the first noteAs 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 improvementsThe 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:
- Fix the typos mentioned in the review comments.
- Consider enhancing the clarity of some sentences, as suggested.
- 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 issueFix 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:
- Effective state management using useState and useEffect.
- Proper integration with on-chain data through custom hooks and SDK.
- A clean and intuitive user interface for theme switching.
Main areas for improvement:
- Optimize useEffect hooks by moving function definitions outside and refining dependency arrays.
- Enhance error handling throughout the component, especially in asynchronous operations.
- Improve performance by preventing unnecessary re-renders and DOM manipulations.
- Consider extracting some logic into custom hooks for better separation of concerns and reusability.
- 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 componentsThe dropdown components are thoughtfully implemented using
React.forwardRef
with appropriate TypeScript typings. Utilizing Radix UI primitives ensures accessibility and consistent behavior. Thecn
utility function effectively manages conditional class names, enhancing styling flexibility.
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]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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:
- Move the
getEntity
function outside the effect to prevent unnecessary re-creation on each render. - Improve error handling by logging specific error messages.
- 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.
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]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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:
- Move the
subscribeToEntityUpdates
function outside the effect to prevent unnecessary re-creation. - Improve error handling with more specific error messages.
- Remove 'theme' from the dependency array to prevent unnecessary re-subscriptions.
- 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.
useEffect(() => { | ||
if (null !== theme.current) { | ||
document.body.classList.remove(theme.current); | ||
} | ||
if (null !== theme.next) { | ||
document.body.classList.add(theme.next); | ||
} | ||
|
||
|
||
}, [theme]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Optimize theme application effect.
The effect correctly applies theme changes to the document body, but there are a few improvements that could be made:
- Add a check to prevent unnecessary DOM manipulations when the current and next themes are the same.
- Ensure that theme classes exist before attempting to add or remove them.
- 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.
const DropdownMenuShortcut = ({ | ||
className, | ||
...props | ||
}: React.HTMLAttributes<HTMLSpanElement>) => { | ||
return ( | ||
<span | ||
className={cn("ml-auto text-xs tracking-widest opacity-60", className)} | ||
{...props} | ||
/> | ||
) | ||
} | ||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
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" |
b65118b
to
96337c9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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 typoThe "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 deploymentThe "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
⛔ 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 handlingThe
cn
function effectively combines the power ofclsx
for conditional class names andtwMerge
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 transliterationThe
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 normalizationThe
toValidAscii
function provides a thorough approach to normalizing strings by removing accents and diacritics. The combination of NFD normalization, regex-based diacritic removal, and theaccentsToAscii
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 introductionThe introduction effectively sets the context for the OnChainDash Vite Kitchen Sink project, highlighting its purpose of showcasing dojo's capabilities beyond gaming.
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
96337c9
to
4104f89
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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 usingcva
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 mappingThe
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 functionThe
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 suggestedThe 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 clarityConsider 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 justforwardRef
.
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 usingReact.forwardRef
and thecn
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, usingReact.forwardRef
and Radix UI's Portal for proper DOM positioning. The conditional styling based on theposition
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 componentThis 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 ofSelectPrimitive.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 logoThe 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 adjustmentThe 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 AccessibleThe close button lacks an explicit
aria-label
, which can improve accessibility for assistive technologies. Consider adding anaria-label
to theDialogPrimitive.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 DocumentationAdding 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
⛔ 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 update
actionscontract address in
src/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 andbadgeVariants
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 suggestionConsider 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:
- The component adds to the kitchen sink example as intended.
- Documentation could be improved by adding JSDoc comments to the Badge component and badgeVariants function.
- Tests should be added to ensure the component behaves as expected.
- 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 functionThe
cn
function is well-implemented, usingclsx
for combining class values andtwMerge
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 functionThe
transliterate
function is well-implemented:
- It uses a functional approach with
split
,map
, andjoin
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 functionThe
accentsToAscii
function is well-implemented:
- It efficiently uses the
transliterate
function with the predefinedcharMap
.- The
charMap
is correctly defined outside the function, addressing the performance concern raised in the previous review.
65-68
: LGTM: Comprehensive ASCII conversion functionThe
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 issueImprove
ensureStarkFelt
implementationThe current implementation of
ensureStarkFelt
still has some potential issues:
- There's no validation to ensure the input is a valid hexadecimal string.
- Inputs longer than 66 characters are not handled explicitly.
- 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:
- Validating that the input is a valid hexadecimal string.
- Always adding the "0x" prefix.
- Ensuring the result is always 66 characters long (including "0x").
- 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 noteAs 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 update
actionscontract address in
src/compon...(AI_EN_LECTOR_MISSING_DETERMINER_THE)
1-49
: Enhance README with additional sectionsAs suggested in a previous review, consider enhancing the README with the following additional sections to make it more comprehensive:
Features Demonstrated
- List the key dojo.js features showcased in this kitchen sink example.
Example Structure
- Provide an overview of how the example is organized.
- Explain how to navigate through different parts of the example.
Learn More
- Include links to dojo.js documentation and other relevant resources.
Contributing
- Add information on how to contribute to improving this example.
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 update
actionscontract address in
src/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:
- Adding a comment to explain the
useDojoDb
hook.- Implementing user-friendly error messages for failed message publishing.
- Using the functional update form of
setMessages
for more reliable state updates.- 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
, andSelectValue
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
andSelectScrollDownButton
components are consistently implemented usingReact.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 usingReact.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 usingReact.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 declarationThe imports are well-organized and the
Header
component is correctly declared as a functional component.
1-169
: Overall assessment: Well-implemented header componentThe
Header
component is well-structured and aligns with the PR objective of adding a kitchen sink example to the dojo.js project. It includes:
- A logo and title for the "OnChain Dash" application
- A settings drawer with model configuration options
- Theme switching and wallet account integration
- 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
anduseState
hooks is appropriate for managing the component's state and wallet connection functionality.
165-165
:⚠️ Potential issueFix 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 ComponentsThe new dialog components are well-implemented, leveraging Radix UI primitives effectively. The use of
React.forwardRef
and properdisplayName
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 ComponentsThe 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.
export interface BadgeProps | ||
extends React.HTMLAttributes<HTMLDivElement>, | ||
VariantProps<typeof badgeVariants> { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Missing Tests and Documentation for Drawer Components
The verification indicates that the following PR objectives are not fully met:
- Tests: No test files found for the Drawer components.
- Documentation: No documentation files found for the new Drawer components.
- 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:
- The implementation of this kitchen sink example for the Drawer component is a valuable addition to the dojo.js project.
- 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:
- Are tests for these components implemented in a separate file?
- Is there documentation for these new Drawer components?
- 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
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]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider optimizing useEffect hooks and improving error handling.
The useEffect hooks handle the necessary logic for theme management, but there are some potential improvements:
- Consider extracting the getEntity and subscribeToEntityUpdates functions outside the useEffect to prevent unnecessary re-creation.
- Improve error handling by providing more specific error messages and potentially implementing a retry mechanism.
- 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.
<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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve accessibility in the settings drawer
The settings drawer is well-structured, but there are some accessibility improvements to be made:
- The
Select
components for "Model" and "Role" are not properly associated with their labels. - The icon sizes are still using className instead of the
size
prop.
Please apply the following changes:
- For the "Model" select:
- <Select>
+ <Select id="model">
- For the "Role" select:
- <Select defaultValue="system">
+ <Select id="role" defaultValue="system">
- 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.
<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> |
const walletIdToName = new Map([ | ||
["argentX", "Argent X"], | ||
["braavos", "Braavos"], | ||
["argentWebWallet", "Email"], | ||
["argentMobile", "Argent mobile"], | ||
]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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 purposeTo 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 thechildren
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 = 200This 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-configThis 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:
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.
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.
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
includeargent
andbraavos
, 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 andAvailableThemeClassMap
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:
- Implement components that utilize these models and schema.
- Create example usage of the Dojo Engine SDK with this schema.
- Add unit tests to ensure the correctness of the schema and any related functionality.
- Update the project documentation to explain how to use this kitchen sink example.
- 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 improvementThe 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 commentsThe
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 optimizationsThe Button component implementation is solid and handles various cases well. The use of
forwardRef
and the handling of theasChild
prop provide great flexibility.To potentially improve performance, consider these optimizations:
- 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 ... } -) +))
- 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
⛔ 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 structureThe 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 styleThe 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, theRootLayout
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:
- Ensure that this example is thoroughly tested.
- Update relevant documentation to explain the purpose and usage of this kitchen sink example.
- 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 extendsSchemaType
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 theOnchainDashSchemaType
interface.Could you please explain the significance of using 9999999 as the key for
global_counter_key
andtheme_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 flexibleThe export statement is concise and provides good flexibility by exporting both the
Button
component and thebuttonVariants
. This allows users of the module to use the pre-defined styles separately if needed.
1-6
: 🛠️ Refactor suggestionConsider 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 thearia-label
for the Help buttonThe
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 ReviewThe 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:
- The component structure is generally well-organized and follows React best practices.
- Wallet connection functionality is implemented using the @starknet-react/core library.
- The UI includes tooltips and a modal dialog for improved user experience.
Recommendations for improvement:
- Enhance error handling and user feedback for wallet connection attempts.
- Optimize the nesting of Tooltip and Dialog components for better readability.
- Implement safeguards for potentially undefined connector icons.
- 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.
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', | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add 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<{}>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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)
## (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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
## (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 |
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> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 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:
- Update documentation to explain the usage of this new component.
- Add tests to verify the component's behavior.
- Create a dedicated CI job for the new examples, if not already done.
- 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
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]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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:
- Extract the
getEntity
andsubscribeToEntityUpdates
functions outside the useEffect hooks to improve readability and reusability. - Address TypeScript errors and avoid using
@ts-expect-error
. Instead, properly type the responses from the database. - Improve error handling by providing more specific error messages and potentially implementing a retry mechanism.
- 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.
useEffect(() => { | ||
document.body.classList.forEach((cls) => document.body.classList.remove(cls)); | ||
if (null !== theme.next) { | ||
document.body.classList.add(theme.next); | ||
} | ||
}, [theme]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
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]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
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]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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:
- Add a state variable for error messages:
const [errorMessage, setErrorMessage] = useState<string | null>(null);
- 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]);
- 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.
<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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Optimize component structure and enhance error handling
-
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>
-
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. -
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.
00427bc
to
6a8d9f0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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 ofStarknetProvider
andTooltipProvider
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:
- Implement actual settings in the settings section or add a TODO comment explaining what settings are planned.
- 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:
- If the Chat component supports configuration options, consider passing them as props to demonstrate their usage in the kitchen sink example.
- 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:
- Implement the missing functionality in the settings and stats sections.
- Address the unused imports or clarify their intended use.
- Consider the performance optimizations and accessibility improvements suggested in previous comments.
- Add unit tests for the
Home
component and its child components.- Update the documentation to explain the purpose and usage of this kitchen sink example.
- 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 mappingThe
charMap
is well-defined with a comprehensive list of accented characters and their ASCII equivalents. Defining it outside theaccentsToAscii
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 prerequisitesThe 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 suggestionThe
buttonVariants
definition usingcva
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 suggestionThe Button component is well-implemented, using
forwardRef
for proper ref handling, providing flexibility with theasChild
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 fortext-wrap: balance
.The
text-balance
utility class uses thetext-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 tohandleCallerClick
The contract write setup looks good, and you've addressed the previous comment about hard-coding contract addresses by using
dojoConfig
. However, thehandleCallerClick
function doesn't handle potential errors fromincrementCallerCounter
. 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 goodThe 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 componentThis 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
⛔ 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 update
actionscontract address in
src/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 issueSimplify 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 functionThe
cn
function is well-implemented, usingclsx
for combining class values andtwMerge
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 functionThe
transliterate
function is well-implemented:
- It uses a functional approach with
split
,map
, andjoin
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 functionThe
accentsToAscii
function is well-implemented and optimized:
- It uses the
transliterate
function with the pre-definedcharMap
.- 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 functionThe
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 functionThe
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 issueFix 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 update
actionscontract address in
src/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-organizedThe 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 interfaceThe
ButtonProps
interface is well-structured, extending appropriate types and adding useful custom props. TheasChild
prop enhances composability, while theloading
prop provides a convenient way to handle async operations.
62-62
: LGTM: Appropriate exportsExporting both the
Button
component and thebuttonVariants
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 goodThe 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-implementedThe 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 theloading
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 necessaryAll 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-exportedThe Dialog primitives (
Dialog
,DialogTrigger
,DialogPortal
,DialogClose
) are appropriately assigned and ready for use in the component hierarchy.
15-28
:DialogOverlay
component is properly implementedThe
DialogOverlay
component correctly usesReact.forwardRef
to forward refs, and it spreads additional props as expected. The class names are managed using thecn
utility, which ensures conditional class application.
30-52
:DialogContent
component is well-structured with accessibility considerationsThe
DialogContent
component wraps content withinDialogPortal
and includesDialogOverlay
, ensuring proper layering of the dialog. It correctly forwards refs and applies class names for styling and animations. The inclusion of theDialogPrimitive.Close
component with an accessible name enhances usability.
54-66
:DialogHeader
component is neatly definedThe
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 designThe
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 stylesThe
DialogTitle
component usesReact.forwardRef
and applies semantic HTML elements with appropriate styling, contributing to the dialog's accessibility.
97-107
:DialogDescription
component enhances accessibilityBy providing a styled description component that forwards refs, the
DialogDescription
promotes better accessibility practices within dialogs.
109-120
: Export statements are comprehensiveAll components are correctly exported, allowing easy import and usage throughout the project.
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; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve ensureStarkFelt
implementation
The current implementation of ensureStarkFelt
still has some potential issues:
- There's no validation to ensure the input is a valid hexadecimal string.
- Inputs longer than 66 characters are not handled explicitly.
- The behavior for inputs not starting with "0x" might be unexpected.
Consider implementing the following improvements:
- Validate that the input is a valid hexadecimal string.
- Handle inputs longer than 66 characters (e.g., truncate or throw an error).
- 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:
- The input is a valid hexadecimal string.
- The "0x" prefix is always added.
- The result is always 66 characters long (including "0x").
- 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.
# OnChainDash Vite Kitchen Sink | ||
|
||
This project aims at showcasing dojo's capabilities outside of gaming. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance the introduction with more context and explanation
The introduction provides a basic overview, but it could be more informative. Consider the following improvements:
- Add a brief explanation of what dojo.js is for context.
- Clarify what a "kitchen sink" example means in this context.
- 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)
katana --disable-fee --allowed-origins "*" | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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:
- For the katana command, add an option to specify the network:
katana --disable-fee --allowed-origins "*" [--network <network_name>]
- 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
# 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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:
-
Project Structure: Provide an overview of the project's directory structure and main components.
-
Features Demonstrated: List and briefly explain the dojo.js features showcased in this kitchen sink example.
-
Configuration: If there are any configuration options or environment variables, document them here.
-
Troubleshooting: Add a section with common issues and their solutions.
-
Contributing: Include guidelines for how others can contribute to this example project.
-
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 update
actionscontract address in
src/compon...(AI_EN_LECTOR_MISSING_DETERMINER_THE)
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]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
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]); |
)} | ||
{...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, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 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:
- The implementation successfully adds a kitchen sink example for select components, enhancing the dojo.js project.
- The code demonstrates good quality and adherence to best practices.
To fully complete the PR objectives:
- Ensure that documentation is updated to reflect these new components.
- Add unit tests to verify the functionality of these components.
- Consider creating a dedicated CI job for testing these new examples.
- 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
const handleChangeTheme = useCallback(async (theme: AvailableTheme) => { | ||
setIsLoading(true); | ||
await writeAsync({ | ||
calls: [{ | ||
contractAddress: dojoConfig.manifest.contracts[0].address, | ||
entrypoint: "change_theme", | ||
calldata: [theme] | ||
}] | ||
}) | ||
}, [writeAsync]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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]); |
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
<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} | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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
Closes #
Introduced changes
Checklist
Summary by CodeRabbit
New Features
CallerCounter
,Chat
,GlobalCounter
,Header
,Sidebar
,StarknetProvider
,ThemeSwitchButton
, and various reusable UI elements.Documentation
Chores
.gitignore
to exclude local Netlify folder.