/
Documentation

Documentation



Libraries:

  • React – JavaScript library for making complex UI in a performant and maintainable way

  • Material UI – a collection of pretty pre-made UI components, designed according to well-researched UI standards

  • Cypress – an end-to-end testing library

    • Running Cypress tests will involve literally spinning up a browser and executing automated actions like clicking on buttons and asserting results after those actions

  • Jest – a unit testing library

    • When used with React Testing Library, it lets you check whether React components will have the HTML or state that you expect when an event takes place. Eg. after you perform user actions like button clicks, you might assert that a counter value goes up.

  • Various other libs – npm has a huge amount of great libraries. We’re using a number of them such as react-console-emulator, react-helmet, react-cookie, etc.

    • It’s preferable to not re-invent the wheel, but we should be careful not to bloat our package.json with poorly-supported dependencies.

Directory Structure:

Below is a breakdown of the client directory structure. This should be used as a reference for figuring out which part of the codebase is responsible for doing or displaying what.

  • For people working on the UI and design, you mainly need to be aware of what’s inside client/components and client/views.

    • For people working on the visualiser UI specifically (the controller, terminal, etc.

  • For people working on the visualiser, you mainly need to be aware of what’s inside visualiser-src.

  • For anyone trying to add a new visualiser and its commands into our webpage, see the section 'Adding a New Visualiser'.

You shouldn’t worry about any file you see in the project that isn’t included in the client directory, eg. Dockerfiles, Jest config, build folders, etc.

client/ package.json src/ App.scss # Contains styles that we want globally applied, eg. scrollbar styles, default fonts, etc. App.tsx # The root React UI component. This is where you should add new routes. assets/ # A bunch of images, fonts and other static content that you wouldn't put next to your source code components/ # All our React components (minus the pages themselves - those belong in the 'views' directory!) Autocomplete # Basically a dropdown that suggests autocompletion results. See mui.com/components/autocomplete/. Features # Some components used to help showcase our project features on the landing page. FloatingWindow # The collapsible floating window on the visualiser, used for the operations menu and the code snippets Footer # Footer element at the bottom of some pages, showing social links and links to other places. Frame # Literally like picture 'frames', used to decorate showcase images Gallery # A pretty container for pictures. Used to showcase a collection of items that have pictures. See mui.com/components/image-list/. HorizontalRule # Basically prettier <hr /> components. See mui.com/components/dividers/. Loader # Some fancy spinners, used to show some content is loading. See mui.com/components/progress/. Navbars # Top navbar and side navbar PageLayout # Contains some fundamental UI that is reused by our pages. Eg. the topnav, some container padding, etc. Tags # A list of 'chip' components. It's mainly used to show tags for a topic like "COMP2521", "COMP1511", etc. See mui.com/components/chips/. Topics # Contains the UI cards for all the topics (linked list, BST, etc.) that appear on the homepage. Visualiser # Our visualiser UI. This includes the controller UI, terminal, GUI form, etc. # This DOES NOT include any visualiser implementation! This is purely the surrounding UI. For the actual implementation, see 'visualiser-src' constants/ # Contains global config and values that would otherwise be hard-coded in our source code. api.ts # This contains important API connection info, eg. what the API URL is. cookies.ts # This contains the names of cookies we're using. Eg. We need a name for the cookie that tracks whether the user should have dark mode on or off. main.tsx # The REAL root UI component. This should rarely be touched unless we're doing fundamental changes. See 'App.tsx'. structsThemes.ts # Our colour palette! utils/ # A bunch of reusable functions. apiRequests.ts # Contains all the functions you need to grab or change content from the API. Eg. there's functions for fetching lessons, topics, etc. markdown-util.ts # Some functions for working with markdown. Notification.ts # Spawns a small notification/popup. Great for non-invasive error messages and communicating short messages with the user. url.ts # Some string manipulation functions, specifically for working with URL-like strings. pages/ # Our pages. These are React components that specifically define page layout and content. For specific UI elements, see 'components'. Feedback.tsx HomePage.tsx # Our landing page. Page404.tsx # A cool 404 page for when the user navigates to a route that we haven't defined. Eg. structs.sh/non-existent-page. VisualiserPage.tsx visualiser-src/ # Our visualiser source code. All the internal visualiser magic happens here. This does NOT define anything related to UI - for that, see 'components/Visualiser'. binary-search-tree-visualiser/ # BST visualiser layout and operations. Includes things like insertion, rotation, etc. and drawing the tree. controller # Executes controller operations like play, pause, speed change, etc. and manages state such as the animation timeline and operations history. linked-list-visualiser # Linked list visualiser layout and operations. Includes things like insertion, deletion, etc. and drawing the linked list. typedefs.ts # Custom data types used by the Visualiser implementation.

Styling with styled components

Using global CSS/SCSS is a nightmare in a large project because you will likely encounter name collisions and CSS specificity issues.

Using inline styles is limited (doesn’t allow for self-selectors like &, pseudo-selectors like :hover, media queries etc.)

To style a component, we can use Material UI styled components:

  1. Suppose you’re working on Menu.jsx.

  2. At the top of the file, write a styled component

const Container = styled('div')(({ theme }) => ({ margin: 10px, }))
  1. Use the styled component in the JSX

const Menu = () => { return <Container>...<Container /> }

Visualiser Docs:

This section provides a high-level explanation of the architecture behind the visualiser’s internal logic.
The visualiser logic and source code exists separately to the React codebase.

Diagram:

This diagram below was built with LucidChart. It shows a bird’s-eye view of the classes and files used to build the visualiser and controller.

Adding a New Visualiser:

To add a new visualiser, you’ll need to need to make a new directory under visualiser-src and create files that follow a similar architecture as above. Use the existing linked-list-visualiser and binary-search-tree-visualiser as references.

Note that you won’t need to create the AnimationController and AnimationProducer classes – they already exist.

To make it show up on the React client, you must

  1. Add an entry for the visualiser into the ‘Topics’ section of the database

  2. Add an entry for the visualiser in the DataStructure enum type under visualiser-src/common/typedefs.ts (make sure the name is consistent with the lowercase version of the database topic title)

  3. Add a case statement for your data structure under visualiser-src/common/GraphicalDataStructureFactory.ts to return your GraphicalDataStructure.

Adding a New Operation to a Visualiser:

Creating the logic of the animations

  1. Code up the operation in the corresponding Graphical[DataStructure] in a new method. Add documentation for the arguments it accepts.

    1. Note: for now, arguments are non-negative integers between 0 and 999 only.

  2. Write up a code snippet in a separate file (in C, as a multi-line string). This should look similar to what you wrote in step 1.

  3. Identify the lines you want to animate and design the look of the animation

    1. This is up to you (be as creative as you want!), but make sure it’s consistent with the rest of the visualiser, and make sure it is true to the steps of the operation.

  4. Add a [DataStructureOperation]AnimationProducer class file under the animation-producer directory in the corresponding data structure directory in visualiser-src

  5. Code up the SVG animations for each line you want to animate – one method corresponding to each code snippet line you identified in step 3.

    1. Write a method that renders a code snippets you wrote in step 2. Make use of the renderCode(code: string) method.

    2. This involves calling addSequenceAnimation for animations that happen at the same time.

    3. TIP: Name AnimationProducer methods after the semantics of each line as opposed to its visuals. For example, .appendNode() as opposed to .showSVGAtLastPosition(). This will guide you on what the animation looks like, and decrease your chances of creating animations that are misleading.

    4. TIP: Before writing an AnimationProducer method, have a look to see whether other operations already have it.

  6. Instantiate the [DataStructureOperation]AnimationProducer class in the method you wrote in step 1 and render the code snippets.

  7. Call doAnimation (in the case that there is no corresponding code snippet line) or doAnimationAndHighlight (to highlight a code snippet line for the duration of your animation) on the AnimationProducer method and its arguments.

  8. Return the AnimationProducer from the method.

If unsure, check out the linked list and binary search tree visualiser as reference.

 

Related content