tarasglek / chatcraft.org

Developer-oriented ChatGPT clone
https://chatcraft.org/
MIT License
147 stars 26 forks source link

Allow exporting/copying to OpenAI format JSON, YAML, fix menus, remove chat header menu #608

Closed humphd closed 2 months ago

humphd commented 2 months ago

This is the export part of #607. I'm not sure what the right UX is for import...

The PR adds support for exporting (download or copy) a chat as OpenAI formatted JSON and YAML:

Screenshot 2024-04-21 at 1 17 59 PM

I've removed the Chat Header menu, since we do everything and more via the Options button/menu now.

I've fixed our custom Menu components to work better with Chakra colors, zIndex, naming for isDisabled prop, passing your own menu button, etc. and reworked the other users of it.

tarasglek commented 2 months ago

Having both download and copy further multiplied by all the download formats ia bit weird, but I can't decide which I like better :)

tarasglek commented 2 months ago

I noticed Options/Clear does not work anymore

humphd commented 2 months ago

I noticed Options/Clear does not work anymore

really? It's working for me. So nothing happens? Any console log?

cloudflare-pages[bot] commented 2 months ago

Deploying chatcraft-org with  Cloudflare Pages  Cloudflare Pages

Latest commit: ac60928
Status: ✅  Deploy successful!
Preview URL: https://bc9aa21b.console-overthinker-dev.pages.dev
Branch Preview URL: https://humphd-export-openai.console-overthinker-dev.pages.dev

View logs

humphd commented 2 months ago

Pushed some fixes.

I'm not sure that I like "Download" since it implies that we've hosted this "on the web" vs. "in your browser." I wonder if "Export" would be better, and also pave the way for "Import"?

Another thing I think is wrong is using the copy/download icons each time for all menu items.

@Amnish04 I'm not sure how to fix the width, position of the menu. Any ideas?

Amnish04 commented 2 months ago

I'm not sure that I like "Download" since it implies that we've hosted this "on the web" vs. "in your browser." I wonder if "Export" would be better, and also pave the way for "Import"?

Export sounds good to me.

Another thing I think is wrong is using the copy/download icons each time for all menu items.

I tried to have the icon only on the Submenu item.

SubMenu.tsx

import { Flex, Icon, useTheme } from "@chakra-ui/react";
import { SubMenu as ReactMenuSubMenu, type SubMenuProps } from "@szhsin/react-menu";
import React from "react";
import { IconType } from "react-icons";

type ReactSubMenuProps = Omit<SubMenuProps, "label"> & {
  label: string;
  icon?: IconType;
  iconSpacing?: number;
};

const SubMenu: React.FC<ReactSubMenuProps> = ({ color, label, icon, iconSpacing, ...props }) => {
  const theme = useTheme();

  const toCssColor = (colorValue?: string) => {
    if (!colorValue) {
      return undefined;
    }

    // Check for ChakraUI colors vs normal CSS (e.g., "red.400")
    if (!/\w+\.\d+/.test(colorValue)) {
      return colorValue;
    }

    const [color, shade] = colorValue.split(".");
    return theme.colors[color]?.[shade];
  };
  return (
    <ReactMenuSubMenu
      itemProps={{ style: { color: toCssColor(color) } }}
      align="center"
      {...props}
      label={
        <Flex gap={iconSpacing ?? 2} alignItems={"center"}>
          {icon && <Icon as={icon}></Icon>}
          {label}
        </Flex>
      }
    >
      {props.children}
    </ReactMenuSubMenu>
  );
};

export default SubMenu;

OptionsButton.tsx

<SubMenu label="Copy" icon={TbCopy}>
  <MenuItem isDisabled={!chat} onClick={() => handleCopyAsMarkdown()}>
    Copy as Markdown
  </MenuItem>
  <MenuItem isDisabled={!chat} onClick={() => handleCopyAsJson()}>
    Copy as JSON
  </MenuItem>
  <MenuItem isDisabled={!chat} onClick={() => handleCopyAsYaml()}>
    Copy as YAML
  </MenuItem>
</SubMenu>
<SubMenu label="Download" icon={TbDownload}>
  <MenuItem isDisabled={!chat} onClick={handleDownloadMarkdown}>
    Download as Markdown
  </MenuItem>
  <MenuItem isDisabled={!chat} onClick={handleDownloadJson}>
    Download as JSON
  </MenuItem>
  <MenuItem isDisabled={!chat} onClick={handleDownloadYaml}>
    Download as YAML
  </MenuItem>
</SubMenu>

And this is how it looks image

@Amnish04 I'm not sure how to fix the width, position of the menu. Any ideas?

I have posted my research regarding this in our original conversation.

tarasglek commented 2 months ago

@humphd no console logs, here is a video recording of clear not working:

https://github.com/tarasglek/chatcraft.org/assets/857083/5e4d1452-d4f4-4aae-bf42-ecd25890218f

Works fine on prod site

humphd commented 2 months ago

@Amnish04 can you take another look? I've made changes based on your review.

I think everything is good now except the broken "Clear" menu item that @tarasglek noticed (I have confirmed that it breaks in the preview URL, but works locally).

// before
        <MenuItem as={ReactRouterLink} to="/new" target="_blank">
          Clear
        </MenuItem>

// after
      <MenuItem>
        <Link as={ReactRouterLink} to="/new">
          Clear
        </Link>
      </MenuItem>

Not sure what I'm doing wrong here, or if the preview URLs are handling things weird? Seems like prod will fail with this, though.

Amnish04 commented 2 months ago

@Amnish04 can you take another look? I've made changes based on your review.

@humphd Looks good for the most part!

Just wondering if should we also rename the toast messages to use "Export" instead of "Download". image

Not sure what I'm doing wrong here, or if the preview URLs are handling things weird? Seems like prod will fail with this, though.

For the Clear option, I guess the problem is that Link element does not take full width and height in a menu item (It works when you click on the text part).

We could probably wrap the entire MenuItem in a Link

<Link as={ReactRouterLink} to="/new" _hover={{ textDecoration: "none" }}>
  <MenuItem>Clear</MenuItem>
</Link>
humphd commented 2 months ago

@Amnish04 take a look at these changes. I created a new MenuItemLink component to deal with the special cases for handling links.

I also fixed the download vs. exported titles/labels.