DEV Community

Cover image for KendoReact Challenge: Epicure's Lost Recipes
Paul
Paul

Posted on

KendoReact Challenge: Epicure's Lost Recipes

This is a submission for the KendoReact Free Components Challenge.

What I Built

Earlier this year, a company called Epicure closed down their business and website. They were primarily focused on cooking products, but they also had over 3,000 recipes on their site which were no longer accessible. I built a NextJS static site using data scraped from the Internet Archive to resurrect Epicure's lost recipes. When I built this website, I originally created it using MUI components. For this challenge, I have created a branch of that project using KendoReact components instead.

Demo

Take a look at the KendoReact Challenge branch of epicure-recipes here:
https://deploy-preview-23--epicure-recipes.netlify.app/

And if you'd like, browse the source code here:
https://github.com/peiche/epicure-recipes/tree/kendo-challenge/

Here are a few screenshots of the website's different browsing capabilities. It is possible to view recipes in a list; recipes tagged under a category; and recipes tagged as using a particular Epicure product. This can vary widely, since Epicure made seasoning packets and jars, as well as kitchen utensils and tools like burger presses and microwave steamers.

Main list of recipes

When I was scraping data from Epicure's recipes, I found that each page contained data in JSON format that contained not only the recipe itself, but also category and product information. This made it quite easy for me to build out tag and product pages as well. I don't have any interest in upselling their products, of course. I'm not affiliated with Epicure, and they aren't manufacturing any new ones, anyway. But it is useful to know what products are used in a recipe, and if you have one of those products, the ability to find more recipes that use it.

List of recipes with a single tag

List of recipes with a single product

Because this is a static site built from JSON data, there is no way to reorder recipes on any given page (although the metadata for dates published and the like does exist in the original JSON). These pages are good for browsing, but if you're looking for a specific recipe, you're better off using the search page.

The search is built using Algolia's InstantSearch for React. I mentioned that the site is built on static JSON data; that very same data was also used to generate the Algolia search index.

The site's search is separated into two parts. The first is the search page, which uses the aforementioned index. Since I already have data for tags and products, it required no extra effort on my part to include that data as facets.

List of recipes in a search result

List of recipes in a search result, with facets checked

The second part of the search is the suggest, which Algolia offers as a "learning" index. It uses the primary search index and updates it based on usage, adding and modifying records as people use the site.

The default query suggestions

The query suggestions with matching results

KendoReact Experience

Below is a list of KendoReact components I used in the project, followed by some custom work when they couldn't offer enough functionality or customization for my liking.

Typography

This is a pretty obvious one, and almost shouldn't even count in the list of components. But it is one, since with this single component one can render a variety of typography-related tags.

Button

Buttons are used throughout the site, primarily for functionality that doesn't directly result in navigation to a different page. This includes things like the Search button in the navbar and pagination on the search page.

Search result pagination

The difficulty I encountered with converting from MUI to KendoReact was that Kendo's Button component can't be a link. It can only render a <button> element, never a <a>. Sure, you can set the onClick event to trigger navigation, but for SEO purposes I prefer to render a link. To that end, there are instances on the site where I manually created anchor elements that merely look like buttons using the same CSS classes as the Button component. You can see an example of this in the "button" on the homepage.

The site homepage

AppBar

The site's top navigation uses this, along with subsequent components. Rather than use display: flex in custom CSS to create spacing, I was able to leverage the AppBarSection and AppBarSpacer components with zero utility class usage.

GridLayout and GridLayoutItem

In places where I needed to create a grid, such as the list pages and search results, I used these components. Unlike MUI's Grid counterpart, these use display: grid rather than display: flex. I am less familiar with CSS Grid than I am with Flex, but making a symmetrical layout is simple enough.

List of recipes with a single tag

What I did have issues with is making the layout responsive. I found tutorials on how to do so with KendoReact (like this one) that require extensive configuration or creating a listener to window resizing. None of that appealed to me, so I created a couple utility classes in my stylesheet, one for a two-column layout (used on the search results page) and one for a thee-column layout (used on all the list grid pages).

Card

Inside every GridLayoutItem component was a shared recipe card component, which used Card and subsequent components, like CardImage, CardHeader, and CardBody. Some style specificity I had to override with the utility classes provided by the themes' stylesheets (more on that later).

TextBox

I don't have much by way of forms on the site, but there are two: the search suggest and the search results page itself.

Chip

You might think that I'm using the Chip component on the recipe detail page, but you'd be wrong. Those are actually a custom component with all the classes to recreate the appearance of a Chip. The reason I didn't use the KendoReact component is simple: you can't make it a link, only a button. For SEO purposes, I prefer to use a link when navigation is required.

The recipe detail page's tag links

On the search results page, however, I am using the Chip as provided by KendoReact. There's no navigation there: clicking on one of those will rearrange the search filters. The hit count next to each facet is also a Chip, but used solely for its display design.

List of recipes in a search result, with facets checked

Checkbox

On the search results page, each facet is represented by a checkbox. Checking it will filter according to that selection; unchecking it will undo the selection.

Dialog

To pop up the search suggest modal, I'm using the Dialog component. Super simple, and no customization required.

The search suggest dialog

Drawer

Like every page, the search results page is responsive. I designed the entire site to be usable on a phone as well as a computer, and the search is no exception. When your screen is too small to display the search filters alongside the results, I hide the filters in a sidebar. Inside the drawer, the selected facets are also displayed.

Search results with filters hidden

Search results with filters displayed

I did find the Drawer somewhat counterintuitive to use, as the default behavior expects to be given a list of items as navigation. However, there is a component called DrawerNavigation that can be used to manually insert any kind of content inside the drawer.

Switch

I put a Switch in the header to swap between light and dark modes (more on that in a minute). There isn't a whole lot of customization; it only allows for custom text in the different toggle states, and I really wanted to use sun and moon icons. I found a site that lets you search for symbols, so I copied those characters and put them in the text props.

Grid of sun and moon related symbols

The selection defaults to light mode, but switching it saves the change to local storage, allowing a user to keep using that theme without having to click it again the next time they visit.

The site with dark mode enabled

Custom Components

As I mentioned, some of KendoReact's components did not offer enough versatility to use out-of-the-box. I want to talk about those for a minute here.

Button

I already mentioned this one, but I think it bears repeating. Sometimes you want to style a link like a button, and KendoReact does not provide an easy way to do that. Every time I wanted a link that looked like a button, I would create the button, copy its CSS classes, and then manually create the link. (In my case, I used NextJS's Link component.)

{/* Button component */}
<Button
  themeColor='primary'
  fillMode='solid'
>Print</Button>

{/* Recreated link  */}
<Link
  className='k-button k-button-md k-button-solid k-button-solid-primary k-rounded-md'
  href={`/recipe/${slug}/print`}
  target='_blank'
>
  <span className='k-button-text'>Print</span>
</Link>
Enter fullscreen mode Exit fullscreen mode

Chip

The "chips" on the recipe detail page, as I've mentioned, are custom anchor elements. Much like I did with the links that look like buttons, I created a Chip, copied its CSS classes, and created an anchor element with those classes. You can see the custom shared component here:

https://github.com/peiche/epicure-recipes/blob/kendo-challenge/src/components/chipLink.tsx

Pager

As far as I could tell from the documentation, the Pager component was to be used within the context of a data table. I had two use-cases: pagination for the browse pages and the search results page. The former had to result in navigation, so they had to be links. The latter are buttons since they update the page but don't result in navigation away from a page. (The URL does get updated, though, so a specific search result can be linked to.)

I ended up writing my own pagination components, one for each use-case. I briefly considered writing a single component that could handle both, but there is such a thing as over-engineering! 😆 As a result, there are two components, each with identical logic to skip over displaying every single page.

https://github.com/peiche/epicure-recipes/blob/kendo-challenge/src/components/pagination.tsx
https://github.com/peiche/epicure-recipes/blob/kendo-challenge/src/components/searchPagination.tsx

Breadcrumb

The breadcrumb component was another case where the elements could not be given a destination outside of an onClick event. It made even less sense here because each leaf in the breadcrumb's path is an anchor element, but is hard-coded to have "#" as the href value. In order to have a breadcrumb component that rendered functional anchor elements, I wrote my own, using the existing CSS classes used by the Kendo component.

https://github.com/peiche/epicure-recipes/blob/kendo-challenge/src/components/breadcrumbs.tsx

Delightfully Designed

I created an account on Telerik and signed up for the seven-day trial of the Theme Builder pro, just so I could have more than one design. (The free tier has a limit of one.) I created two color themes: one light and one dark.

Light theme in Theme Builder

Dark theme in Theme Builder

I exported the two themes, but my use of the downloads changed over the course of development. I originally used the Sass exports, but I found that the variables used there were Sass variables, not custom properties (i.e., native CSS variables), so I switched to the CSS exports instead. (My separate global stylesheet still uses Sass.)

I initially put the stylesheets inside /src/themes, but moved it into /public because the CSS theme switcher dependency I was using required a static, public URL.

The site with dark mode enabled

Final Notes

I did mention using some utility classes to override some default styles. Before I did a deep dive into the styles included with the theme -- both the base stylesheet and the exported files from Theme Builder -- I considered using Tailwind to supplement what I needed. After some digging, however, I found that Kendo already provided most of what I needed. (I did, as I mentioned, have to create a couple grid-related utility classes.)

I also want to note that while I am using a few icons, none of them are Kendo's. I did start out using them, but there are some they don't have, like the fork and knife icon I'm using on the recipe detail page. I used Font Awesome for that. Rather than have visual inconsistency (heaven forbid!) I decided to make all the icons come from Font Awesome.

The best hobby web apps are the ones you build for yourself. That's no less true in this case, since I use it quite a bit. ("I'm not just the president, I'm also a client!") It's invaluable to me to be able to pull up a recipe on my phone; to that end, the entire site is responsive: from the home page and browse to the search and recipe detail pages. Maybe you can have a use for it too!

Responsive recipe detail page

Thanks for reading!

I've had a lot of fun (and some frustration) in refactoring my existing site to use a new set of components. And if you're a foodie, feel free to poke around my recipe site. It's a labor of love.


I may still write about the process I used to generate the JSON files which form the base of the static site, but that is a story for another time.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (1)

Collapse
 
nazim_akkal_a6c14939d5955 profile image
nazim akkal

so tasty recipes,
hope namine is doing well

Cloudinary image

Zoom pan, gen fill, restore, overlay, upscale, crop, resize...

Chain advanced transformations through a set of image and video APIs while optimizing assets by 90%.

Explore

👋 Kindness is contagious

If you found this post useful, consider leaving a ❤️ or a nice comment!

Got it