KendoReact Playground

This is a submission for the KendoReact Free Components Challenge. What I Built Hey there! I’m Aniruddha Adak, and I built a little web playground that’s basically my excuse to relive my childhood while pretending to be a serious developer. This project is a React app with three sections: a Game Page (think Tetris and Memory Game, but with less yelling at the screen), a Sites Section (fancy dashboards and portfolios because adulting), and a Blocks Page (cool UI bits like login cards and sidebars). It’s all tied together with a snazzy toolbar that screams, “Click me, I’m fun!” I used TypeScript because I like my code to yell at me before it breaks, and Vite because I’m too impatient for slow builds. The result? A fast, interactive app that’s equal parts nostalgia and nerdy joy. Here’s the code that powers it all: Main App (src/App.tsx) This is the heart of my playground—navigation and all! import React from 'react'; import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom'; import { Toolbar, Button } from '@progress/kendo-react-buttons'; import GamePage from './pages/GamePage.tsx'; import SitesSection from './pages/SitesSection.tsx'; import BlocksPage from './pages/BlocksPage.tsx'; const App: React.FC = () => { return ( Games Sites Blocks ); }; export default App; Vite Entry (src/main.tsx) How I get this party started with Vite: import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App.tsx'; ReactDOM.createRoot(document.getElementById('root')!).render( ); Vite Config (vite.config.ts) My Vite setup—keeps things fast and sassy: import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], server: { hmr: { overlay: true, }, }, }); Game Page (src/pages/GamePage.tsx) Where the fun begins—games galore! import React, { useState } from 'react'; import { Button } from '@progress/kendo-react-buttons'; import { Dialog } from '@progress/kendo-react-dialogs'; import MemoryGame from '../components/games/MemoryGame.tsx'; import TetrisGame from '../components/games/TetrisGame.tsx'; interface Game { name: string; component: JSX.Element; } const GamePage: React.FC = () => { const [selectedGame, setSelectedGame] = useState(null); const games: Game[] = [ { name: 'Memory Game', component: }, { name: 'Tetris', component: }, ]; return ( Games {games.map((game, index) => ( setSelectedGame(game.component)}> {game.name} ))} {selectedGame && ( setSelectedGame(null)} width={500}> {selectedGame} )} ); }; export default GamePage; Memory Game (src/components/games/MemoryGame.tsx) Flipping cards like a pro (or a kid with too much sugar): import React, { useState } from 'react'; import { Button } from '@progress/kendo-react-buttons'; import { Animation } from '@progress/kendo-react-animation'; const MemoryGame: React.FC = () => { const [flipped, setFlipped] = useState(Array(4).fill(false)); const handleFlip = (index: number) => { const newFlipped = [...flipped]; newFlipped[index] = !newFlipped[index]; setFlipped(newFlipped); }; return ( {flipped.map((isFlipped, index) => ( handleFlip(index)} style={{ width: '100px', height: '100px' }} > {isFlipped ? '⭐' : 'Back'} ))} ); }; export default MemoryGame; Tetris Game (src/components/games/TetrisGame.tsx) A Tetris wannabe that’s more chill than the real deal: import React, { useState } from 'react'; import { Button } from '@progress/kendo-react-buttons'; import { ProgressBar } from '@progress/kendo-react-progressbars'; const TetrisGame: React.FC = () => { const [score, setScore] = useState(0); const handleAction = () => { setScore((prevScore) => prevScore + 10); }; return ( Tetris Grid Move Block ); }; export default TetrisGame; Sites Section (src/pages/SitesSection.tsx) Where I pretend to be a grown-up with dashboards: import React, { useState } from 'react'; import { Button } from '@progress/kendo-react-buttons'; import { Dialog } from '@progress/kendo-react-dialogs'; import FinancialDashboard from '../components/sites/FinancialDashboard.tsx'; import Portfolio from '../components/sites/Portfolio.tsx'; interface Site { name: string; component: JSX.Element; } const SitesSection: React.FC = () => { const [selectedSite, setSelectedSite] = useState(null); const sites: Site[] = [ { name: 'Financ

Mar 19, 2025 - 18:12
 0
KendoReact Playground

This is a submission for the KendoReact Free Components Challenge.

What I Built

Hey there! I’m Aniruddha Adak, and I built a little web playground that’s basically my excuse to relive my childhood while pretending to be a serious developer.

This project is a React app with three sections: a Game Page (think Tetris and Memory Game, but with less yelling at the screen), a Sites Section (fancy dashboards and portfolios because adulting), and a Blocks Page (cool UI bits like login cards and sidebars).

It’s all tied together with a snazzy toolbar that screams, “Click me, I’m fun!”

I used TypeScript because I like my code to yell at me before it breaks, and Vite because I’m too impatient for slow builds.

The result? A fast, interactive app that’s equal parts nostalgia and nerdy joy. Here’s the code that powers it all:

Main App (src/App.tsx)

This is the heart of my playground—navigation and all!

import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
import { Toolbar, Button } from '@progress/kendo-react-buttons';
import GamePage from './pages/GamePage.tsx';
import SitesSection from './pages/SitesSection.tsx';
import BlocksPage from './pages/BlocksPage.tsx';

const App: React.FC = () => {
  return (
    <Router>
      <Toolbar style={{ marginBottom: '20px' }}>
        <Link to="/games" style={{ marginRight: '10px' }}>
          <Button>GamesButton>
        Link>
        <Link to="/sites" style={{ marginRight: '10px' }}>
          <Button>SitesButton>
        Link>
        <Link to="/blocks">
          <Button>BlocksButton>
        Link>
      Toolbar>
      <Switch>
        <Route path="/games" component={GamePage} />
        <Route path="/sites" component={SitesSection} />
        <Route path="/blocks" component={BlocksPage} />
        <Route path="/" component={GamePage} />
      Switch>
    Router>
  );
};

export default App;

Vite Entry (src/main.tsx)

How I get this party started with Vite:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  React.StrictMode>
);

Vite Config (vite.config.ts)

My Vite setup—keeps things fast and sassy:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  server: {
    hmr: {
      overlay: true,
    },
  },
});

Game Page (src/pages/GamePage.tsx)

Where the fun begins—games galore!

import React, { useState } from 'react';
import { Button } from '@progress/kendo-react-buttons';
import { Dialog } from '@progress/kendo-react-dialogs';
import MemoryGame from '../components/games/MemoryGame.tsx';
import TetrisGame from '../components/games/TetrisGame.tsx';

interface Game {
  name: string;
  component: JSX.Element;
}

const GamePage: React.FC = () => {
  const [selectedGame, setSelectedGame] = useState<JSX.Element | null>(null);

  const games: Game[] = [
    { name: 'Memory Game', component: <MemoryGame /> },
    { name: 'Tetris', component: <TetrisGame /> },
  ];

  return (
    <div style={{ padding: '20px' }}>
      <h1>Gamesh1>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '20px' }}>
        {games.map((game, index) => (
          <Button key={index} onClick={() => setSelectedGame(game.component)}>
            {game.name}
          Button>
        ))}
      div>
      {selectedGame && (
        <Dialog title="Play Game" onClose={() => setSelectedGame(null)} width={500}>
          {selectedGame}
        Dialog>
      )}
    div>
  );
};

export default GamePage;

Memory Game (src/components/games/MemoryGame.tsx)

Flipping cards like a pro (or a kid with too much sugar):

import React, { useState } from 'react';
import { Button } from '@progress/kendo-react-buttons';
import { Animation } from '@progress/kendo-react-animation';

const MemoryGame: React.FC = () => {
  const [flipped, setFlipped] = useState<boolean[]>(Array(4).fill(false));

  const handleFlip = (index: number) => {
    const newFlipped = [...flipped];
    newFlipped[index] = !newFlipped[index];
    setFlipped(newFlipped);
  };

  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '10px' }}>
      {flipped.map((isFlipped, index) => (
        <Animation key={index} transitionName={isFlipped ? 'flip' : ''}>
          <Button
            onClick={() => handleFlip(index)}
            style={{ width: '100px', height: '100px' }}
          >
            {isFlipped ? '' : 'Back'}
          Button>
        Animation>
      ))}
    div>
  );
};

export default MemoryGame;

Tetris Game (src/components/games/TetrisGame.tsx)

A Tetris wannabe that’s more chill than the real deal:

import React, { useState } from 'react';
import { Button } from '@progress/kendo-react-buttons';
import { ProgressBar } from '@progress/kendo-react-progressbars';

const TetrisGame: React.FC = () => {
  const [score, setScore] = useState<number>(0);

  const handleAction = () => {
    setScore((prevScore) => prevScore + 10);
  };

  return (
    <div>
      <div
        style={{
          width: '200px',
          height: '400px',
          border: '1px solid black',
          marginBottom: '10px',
        }}
      >
        <p style={{ textAlign: 'center' }}>Tetris Gridp>
      div>
      <Button onClick={handleAction}>Move BlockButton>
      <ProgressBar value={score} max={100} labelVisible={true} style={{ marginTop: '10px' }} />
    div>
  );
};

export default TetrisGame;

Sites Section (src/pages/SitesSection.tsx)

Where I pretend to be a grown-up with dashboards:

import React, { useState } from 'react';
import { Button } from '@progress/kendo-react-buttons';
import { Dialog } from '@progress/kendo-react-dialogs';
import FinancialDashboard from '../components/sites/FinancialDashboard.tsx';
import Portfolio from '../components/sites/Portfolio.tsx';

interface Site {
  name: string;
  component: JSX.Element;
}

const SitesSection: React.FC = () => {
  const [selectedSite, setSelectedSite] = useState<JSX.Element | null>(null);

  const sites: Site[] = [
    { name: 'Financial Dashboard', component: <FinancialDashboard /> },
    { name: 'Portfolio', component: <Portfolio /> },
  ];

  return (
    <div style={{ padding: '20px' }}>
      <h1>Sitesh1>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '20px' }}>
        {sites.map((site, index) => (
          <Button key={index} onClick={() => setSelectedSite(site.component)}>
            {site.name}
          Button>
        ))}
      div>
      {selectedSite && (
        <Dialog title="Site Preview" onClose={() => setSelectedSite(null)} width={600}>
          {selectedSite}
        Dialog>
      )}
    div>
  );
};

export default SitesSection;

Financial Dashboard (src/components/sites/FinancialDashboard.tsx)

Fancy numbers and badges—look at me, adulting!

import React from 'react';
import { Typography } from '@progress/kendo-react-common';
import { Badge } from '@progress/kendo-react-indicators';
import { ProgressBar } from '@progress/kendo-react-progressbars';

const FinancialDashboard: React.FC = () => {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
      <Typography.h2>Financial OverviewTypography.h2>
      <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
        <Typography.p>Revenue: $10,000Typography.p>
        <Badge themeColor="success">+5%Badge>
      div>
      <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
        <Typography.p>Expenses: $7,000Typography.p>
        <Badge themeColor="error">-2%Badge>
      div>
      <ProgressBar value={70} labelVisible={true} />
    div>
  );
};

export default FinancialDashboard;

Portfolio (src/components/sites/Portfolio.tsx)

My imaginary projects, looking sharp:

import React from 'react';
import { Typography } from '@progress/kendo-react-common';
import { Button } from '@progress/kendo-react-buttons';

const Portfolio: React.FC = () => {
  return (
    <div>
      <Typography.h2>Project GalleryTypography.h2>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '20px' }}>
        <div>
          <Typography.h3>Project 1Typography.h3>
          <Button>View DetailsButton>
        div>
        <div>
          <Typography.h3>Project 2Typography.h3>
          <Button>View DetailsButton>
        div>
      div>
    div>
  );
};

export default Portfolio;

Blocks Page (src/pages/BlocksPage.tsx)

UI goodies I can’t stop playing with:

import React, { useState } from 'react';
import { Button } from '@progress/kendo-react-buttons';
import { Dialog } from '@progress/kendo-react-dialogs';
import LoginCard from '../components/blocks/LoginCard.tsx';
import SidebarLayout from '../components/blocks/SidebarLayout.tsx';

interface Block {
  name: string;
  component: JSX.Element;
}

const BlocksPage: React.FC = () => {
  const [selectedBlock, setSelectedBlock] = useState<JSX.Element | null>(null);

  const blocks: Block[] = [
    { name: 'Login Card', component: <LoginCard /> },
    { name: 'Sidebar Layout', component: <SidebarLayout /> },
  ];

  return (
    <div style={{ padding: '20px' }}>
      <h1>Blocksh1>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '20px' }}>
        {blocks.map((block, index) => (
          <Button key={index} onClick={() => setSelectedBlock(block.component)}>
            {block.name}
          Button>
        ))}
      div>
      {selectedBlock && (
        <Dialog title="Block Demo" onClose={() => setSelectedBlock(null)} width={400}>
          {selectedBlock}
        Dialog>
      )}
    div>
  );
};

export default BlocksPage;

Login Card (src/components/blocks/LoginCard.tsx)

A login form that’s simpler than my password:

import React from 'react';
import { Input } from '@progress/kendo-react-inputs';
import { Button } from '@progress/kendo-react-buttons';

const LoginCard: React.FC = () => {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
      <Input label="Username" placeholder="Enter username" />
      <Input label="Password" type="password" placeholder="Enter password" />
      <Button>LoginButton>
    div>
  );
};

export default LoginCard;

Sidebar Layout (src/components/blocks/SidebarLayout.tsx)

A sidebar that pops up like my cat at dinnertime:

import React, { useState } from 'react';
import { Button } from '@progress/kendo-react-buttons';
import { Dialog } from '@progress/kendo-react-dialogs';

const SidebarLayout: React.FC = () => {
  const [isOpen, setIsOpen] = useState<boolean>(false);

  return (
    <div>
      <Button onClick={() => setIsOpen(!isOpen)}>Toggle SidebarButton>
      {isOpen && (
        <Dialog title="Sidebar" onClose={() => setIsOpen(false)} width={200}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
            <Button>Menu Item 1Button>
            <Button>Menu Item 2Button>
          div>
        Dialog>
      )}
    div>
  );
};

export default SidebarLayout;

KendoReact Experience

Oh man, KendoReact’s free components were like my coding fairy godmothers!

I leaned hard on the Button component—those little clickable heroes are everywhere, launching games and toggling sidebars.

The Dialog component was my MVP, popping up games and demos like a jack-in-the-box (but less creepy).

I sprinkled in Animation for that sweet card-flipping action in the Memory Game—because who doesn’t love a little pizzazz?

The ProgressBar kept my Tetris score in check (spoiler: I’m still terrible at it), while Typography made my text look pro without me trying too hard.

Honestly, these components saved me from CSS nightmares and made me look like I know what I’m doing. T

hat was fun—less hair-pulling, more high-fiving myself.

I learned KendoReact is like a cheat code for building fast and pretty!

Happy coding, folks—may your bugs be few and your buttons be plenty!