Skip to content

Icons Proposal

Braulio Diez edited this page Aug 15, 2024 · 8 revisions

Approach

We want the user to be able to add icon shapes, about icons shapes:

  • There will be a shape available to display icons.

  • There will be a list a icons to choose from (it will be stored as static assets, below public or something like that, not included in the bundle "js" deployed as external resource.

  • About the Icon shape it will contain two properties:

    • The url to the icon itself (we will map it to a friendly name).
    • The size of the icon (t-shirt sizes): XS, S, M, L, XL
  • Additional we will create an interface and an array containing the list of icons avaiable (url, name, list of names to search for, list of categories).

About UI, once you drop an icon if you double click on it (or via properties) you can choose the icon from a given list (more on details).

Details

Icon list

Icons will store as static assets, but we need to be able to have a list of icons, and a way to group them by categories (not to be implemented on first instance), and a set of synonyms (e.g. a combobox can have many search terms: 'combobox', 'dropdown').

We will create the following data structure:

// TODO: not sure if it will be /public
const BASE_ICONS_URL = "/";

// TODO Decide list of categories (just 4/5)
type Category = 'IT' | 'business' | 'Ecommerce';

interface IconInfo {
   name : string;
   filename: string;
   searchTerms : string[];
   categories : Category[];
}

Then we can define a list of icons (right now we will define a reduced set of 5 icons to get started), ask @deletidev for this icons and where to obtain them, or initially extract the SVG from our own application (all the sample are from there, but copy them to a public folder).

const IconCollection : IconInfo[] = [
   {name: "New", filename="new.svg", searchTerms: ["new", "white page", "start"], categories: ["IT"]}, 
   {name: "Open", filename: "open.svg",searchTerms: ["open", "folder", "load"], categories: ["IT"]}, 
   {name: "Save", filename: "save.svg",searchTerms: ["save", "disk", "store"], categories: ["IT"]}, 
   {name: "Export", filename: "export.svg",searchTerms: ["export", "upload"], categories: ["IT"]},
   {name: "Undo", filename: "undo.svg",searchTerms: ["undo"], categories: ["IT"]},    
   {name: "Redo", filename: "redo.svg",searchTerms: ["redo"], categories: ["IT"]},    
   {name: "Delete", filename: "delete.svg",searchTerms: ["delete", "remove", "erase", "bin", "trashcan"], categories: ["IT"]},    
   {name: "Zoom out", filename: "zoomout.svg",searchTerms: ["zoom", "zoom out", "magnifier"], categories: ["IT"]},    
   {name: "Zoom in", filename: "zoomin.svg",searchTerms: ["zoom", "zoom in", "magnifier"], categories: ["IT"]},    
   {name: "About", filename: "about.svg",searchTerms: ["about", "group", "people"], categories: ["IT"]},    
]

Model

About the Shape model we will add to optional OtherProps:

./src/core/model/index.ts

+ type IconSize = "XS"| "S" | "M" | "L" | "XL"; 

export interface OtherProps {
  stroke?: string;
  backgroundColor?: string;
+ icon?: IconInfo;
+ iconSize? : IconSize;
}

export interface ShapeModel {
  id: string;
  x: number;
  y: number;
  width: number;
  height: number;
  type: ShapeType;
  allowsInlineEdition: boolean;
  hasLateralTransformer: boolean;
  editType?: EditType;
  text?: string;
  otherProps?: OtherProps;
}

Shape

You can start by adding an static url / info into the shape default creation (just to simplify), you can then:

  • Load the asset, convert it to image.
  • Use the React Konva Image component to render it.

Example creating you own SvgIcon wrapper component:

Install use-image:

npm install use-image --save
import React from 'react';
import { Image } from 'react-konva';
import useImage from 'use-image';

interface SvgIconProps {
  url: string; // URL to the SVG
  x: number;
  y: number;
  width: number;
  height: number;
}

const SvgIcon: React.FC<SvgIconProps> = ({ url, x, y, width, height }) => {
  const [image] = useImage(url);

  return <Image image={image} x={x} y={y} width={width} height={height} />;
};

export default SvgIcon;

And usage of this component:

import React from 'react';
import { Stage, Layer } from 'react-konva';
import SvgIcon from './SvgIcon';

const App: React.FC = () => {
  const svgIconUrl = 'http://localhost:3000/public/myicon.svg';

  return (
    <Stage width={window.innerWidth} height={window.innerHeight}>
      <Layer>
        <SvgIcon url={svgIconUrl} x={50} y={50} width={100} height={100} />
      </Layer>
    </Stage>
  );
};

export default App;

Inline Edit

Once we have the basics with the fixed icon being shown is time to add some additional user interface to let the user choose another icon from a give gallery.

Is time to enhance our inlineEditor (right now it just contains a simple input and a text area), we will enrich them adding a modal dialog that will let the user choose another icon.

In the text property will be temporarily store the name of the svg file.

The initial modal we are going to implement:

image

The one we are going to implement in a second stage:

image

And a more elaborated proposal (todo after the alfa deployment):

image

Properties edit

About properties edition (sidebar), we will add to props:

  • Icon (show the name and a button [...] to change the icon (this will display the modal dialog).
  • Size (with the the five t-shirt sizes options: XS, S, M, L, XL)

image