Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: #7 add color, highlight extensions and fix text align buttons #19

Open
wants to merge 48 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
517e1be
feat: showing character display on the editor
SalahAdDin Jul 20, 2024
41dd071
chore: optimizing count display.
SalahAdDin Jul 20, 2024
b7bfa9d
feat: adding Abbreviation extension
SalahAdDin Jul 20, 2024
7b2f5d2
fix: moving extra components out of toolbar
SalahAdDin Jul 21, 2024
160bd06
chore: remove logging function
SalahAdDin Jul 21, 2024
4b6e2f5
chore: remove logs and unused imports
SalahAdDin Jul 21, 2024
3949830
feat: adding tiptap Alert extension
SalahAdDin Jul 24, 2024
284a8fb
chore: adding extension styles and functionality to the editor
SalahAdDin Jul 24, 2024
2136b2a
chore: adding FloatingMenu extension
SalahAdDin Jul 24, 2024
ee74e01
feat: adding Alert toolbar to handle the alert type
SalahAdDin Jul 24, 2024
2d665ab
chore: remove logs and unused imports
SalahAdDin Jul 21, 2024
64dfb20
chore: adding localization to the editor
SalahAdDin Jul 25, 2024
019179b
chore: adding missing literals for titles
SalahAdDin Jul 25, 2024
0ea7156
fix: adding scroll to editor content
SalahAdDin Jul 20, 2024
af6aeb6
chore: adding localization to the editor
SalahAdDin Jul 25, 2024
dd4d9aa
chore: adding missing literals for titles
SalahAdDin Jul 25, 2024
b2e0af0
chore: adding locale strings
SalahAdDin Jul 25, 2024
6096287
chore: adding localization to the editor
SalahAdDin Jul 25, 2024
650c951
chore: adding missing literals for titles
SalahAdDin Jul 25, 2024
37e683a
chore: adding locale literals
SalahAdDin Jul 25, 2024
17a7edd
chore: adding localization to the editor
SalahAdDin Jul 25, 2024
9ec1680
chore: adding missing literals for titles
SalahAdDin Jul 25, 2024
e6c9d1a
chore: adding localization to the editor
SalahAdDin Jul 25, 2024
e7808c8
chore: adding missing literals for titles
SalahAdDin Jul 25, 2024
9ffaf9a
chore: adding locale literals and fixing some
SalahAdDin Jul 25, 2024
a784bb1
chore: adding locale literals
SalahAdDin Jul 25, 2024
2934f8f
Merge pull request #1 from SalahAdDin/fix/editor-scroll
SalahAdDin Aug 13, 2024
76d7c8d
Merge pull request #2 from SalahAdDin/feat/localization
SalahAdDin Aug 13, 2024
83c3988
Merge branch 'main' into feat/extension-abbr
SalahAdDin Aug 13, 2024
cc5681b
Merge pull request #3 from SalahAdDin/feat/extension-abbr
SalahAdDin Aug 13, 2024
eb4cfcc
Merge branch 'main' into fix/dialogs-in-folder
SalahAdDin Aug 13, 2024
73404fd
Merge pull request #4 from SalahAdDin/fix/dialogs-in-folder
SalahAdDin Aug 13, 2024
9d38658
Merge branch 'main' into feat/character-count-display
SalahAdDin Aug 13, 2024
906fa56
Merge pull request #5 from SalahAdDin/feat/character-count-display
SalahAdDin Aug 13, 2024
27b7c14
Merge branch 'main' into feat/extension-alert
SalahAdDin Aug 13, 2024
2c377e3
Merge pull request #6 from SalahAdDin/feat/extension-alert
SalahAdDin Aug 13, 2024
607165a
fix: adding missing ", on es localization file
SalahAdDin Aug 13, 2024
83faff6
Merge pull request #7 from SalahAdDin/feat/extension-alert
SalahAdDin Aug 13, 2024
e0ffea8
fix: using the proper Youtube icon
SalahAdDin Aug 18, 2024
237abc3
fix: adding text align buttons
SalahAdDin Aug 19, 2024
27eb832
chore: add required dependencies for styles
SalahAdDin Aug 19, 2024
e494720
chore: add color processors
SalahAdDin Aug 19, 2024
1de9d27
chore: enable style extensions for the editor
SalahAdDin Aug 19, 2024
f3a5505
feat: add color picker for Color and Highlight
SalahAdDin Aug 19, 2024
68134e0
chore: add new localized literals
SalahAdDin Aug 20, 2024
dc3e08e
fix: follow proper imports on Color Picker
SalahAdDin Aug 20, 2024
f3ce4fc
fix: parse style colour from either rgb or hex rightly
SalahAdDin Aug 20, 2024
07c3607
fix: disable color and highlight on empty selection
SalahAdDin Aug 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import styled from "styled-components";

export const StyledToolbar = styled("div")`
.is-active {
background: ${({ theme }) => theme.colors.primary200};
color: ${({ theme }) => theme.colors.neutral0};
}

button {
svg {
height: 100%;
width: 100%;
flex-shrink: 0;

rect {
height: 3px;
fill: ${({ theme }) => theme.colors.neutral700};
}
}
svg.extra-icon {
height: 125%;
width: 125%;

#bulb {
fill: ${({ theme }) => theme.colors.neutral100} !important;
}
}
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { IconButton, IconButtonGroup } from "@strapi/design-system/IconButton";
import {
CheckCircle,
CrossCircle,
ExclamationMarkCircle,
Information,
// WarningCircle,
} from "@strapi/icons";
import { Editor, FloatingMenu } from "@tiptap/react";
import { useIntl } from "react-intl";

import { StyledToolbar } from "./AlertToolbar.styles";

export default function AlertToolbar({ editor }: { editor: Editor }) {
const { formatMessage } = useIntl();

return (
<FloatingMenu
editor={editor}
tippyOptions={{ duration: 100 }}
pluginKey="alertToolbar"
shouldShow={({ editor, state }) => {
const { selection } = state;
const { $anchor } = selection;
const isRootDepth = $anchor.depth === 1;

return isRootDepth && editor.isEditable && editor.isActive("alert");
}}
>
<StyledToolbar>
<IconButtonGroup>
<IconButton
icon={<CrossCircle />}
label={formatMessage({
id: "rich-text.editor.toolbar.button.danger",
defaultMessage: "Danger",
})}
onClick={() =>
editor.chain().focus().toggleAlert({ type: "danger" }).run()
}
disabled={
!editor
.can()
.chain()
.focus()
.toggleAlert({ type: "danger" })
.run()
}
className={
editor.isActive("alert", { type: "danger" }) ? "is-active" : ""
}
/>
<IconButton
icon={<Information />}
label={formatMessage({
id: "rich-text.editor.toolbar.button.info",
defaultMessage: "Information",
})}
onClick={() =>
editor.chain().focus().toggleAlert({ type: "info" }).run()
}
disabled={
!editor.can().chain().focus().toggleAlert({ type: "info" }).run()
}
className={
editor.isActive("alert", { type: "info" }) ? "is-active" : ""
}
/>
<IconButton
icon={<CheckCircle />}
label={formatMessage({
id: "rich-text.editor.toolbar.button.success",
defaultMessage: "Success",
})}
onClick={() =>
editor.chain().focus().toggleAlert({ type: "success" }).run()
}
disabled={
!editor
.can()
.chain()
.focus()
.toggleAlert({ type: "success" })
.run()
}
className={
editor.isActive("alert", { type: "success" }) ? "is-active" : ""
}
/>
<IconButton
icon={
// <WarningCircle />
<ExclamationMarkCircle />
}
label={formatMessage({
id: "rich-text.editor.toolbar.button.warning",
defaultMessage: "Warning",
})}
onClick={() =>
editor.chain().focus().toggleAlert({ type: "warning" }).run()
}
disabled={
!editor
.can()
.chain()
.focus()
.toggleAlert({ type: "warning" })
.run()
}
className={
editor.isActive("alert", { type: "warning" }) ? "is-active" : ""
}
/>
</IconButtonGroup>
</StyledToolbar>
</FloatingMenu>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { Select, Option } from "@strapi/design-system/Select";
import { Editor } from "@tiptap/react";
import { useState, useCallback, useEffect } from "react";
import { useIntl } from "react-intl";

export default function BlockTypeSelect({ editor }: { editor: Editor }) {
const [selectedType, setSelectedType] = useState<string>("paragraph");

const { formatMessage } = useIntl();

const onSelect = useCallback((type: string) => {
switch (type) {
case "alert":
editor.chain().focus().setAlert({ type: "info" }).run();
break;
case "h1":
editor.chain().focus().toggleHeading({ level: 1 }).run();
break;
case "h2":
editor.chain().focus().toggleHeading({ level: 2 }).run();
break;
case "h3":
editor.chain().focus().toggleHeading({ level: 3 }).run();
break;
case "h4":
editor.chain().focus().toggleHeading({ level: 4 }).run();
break;
case "h5":
editor.chain().focus().toggleHeading({ level: 5 }).run();
break;
case "h6":
editor.chain().focus().toggleHeading({ level: 6 }).run();
break;
case "blockquote":
editor.chain().focus().toggleBlockquote().run();
break;
case "orderedList":
editor.chain().focus().toggleOrderedList().run();
break;
case "bulletList":
editor.chain().focus().toggleBulletList().run();
break;
case "paragraph":
editor.chain().focus().setParagraph().run();
break;
}

setTimeout(() => {
editor.commands.focus();
}, 50);
}, []);

const setActiveType = useCallback(() => {
if (editor.isActive("heading", { level: 1 })) setSelectedType("h1");
if (editor.isActive("heading", { level: 2 })) setSelectedType("h2");
if (editor.isActive("heading", { level: 3 })) setSelectedType("h3");
if (editor.isActive("heading", { level: 4 })) setSelectedType("h4");
if (editor.isActive("heading", { level: 5 })) setSelectedType("h5");
if (editor.isActive("heading", { level: 6 })) setSelectedType("h6");
if (editor.isActive("alert")) setSelectedType("alert");
if (editor.isActive("paragraph")) setSelectedType("paragraph");
if (editor.isActive("blockquote")) setSelectedType("blockquote");
if (editor.isActive("orderedList")) setSelectedType("orderedList");
if (editor.isActive("bulletList")) setSelectedType("bulletList");
}, []);

useEffect(() => {
editor.on("selectionUpdate", setActiveType);
return () => {
editor.off("selectionUpdate", setActiveType);
};
}, [editor]);

return (
<Select
required
size="S"
placeholder={formatMessage({
id: "rich-text.editor.toolbar.placeholder.text-style",
defaultMessage: "Text Style",
})}
onChange={onSelect}
value={selectedType}
>
<Option value={"paragraph"}>
{formatMessage({
id: "rich-text.editor.toolbar.select.paragraph",
defaultMessage: "Paragraph",
})}
</Option>
<Option value={"h1"}>
{formatMessage({
id: "rich-text.editor.toolbar.select.heading-1",
defaultMessage: "Heading 1",
})}
</Option>
<Option value={"h2"}>
{formatMessage({
id: "rich-text.editor.toolbar.select.heading-2",
defaultMessage: "Heading 2",
})}
</Option>
<Option value={"h3"}>
{formatMessage({
id: "rich-text.editor.toolbar.select.heading-3",
defaultMessage: "Heading 3",
})}
</Option>
<Option value={"h4"}>
{formatMessage({
id: "rich-text.editor.toolbar.select.heading-4",
defaultMessage: "Heading 4",
})}
</Option>
<Option value={"alert"}>
{formatMessage({
id: "rich-text.editor.toolbar.select.alert",
defaultMessage: "Alert",
})}
</Option>
<Option value={"blockquote"}>
{formatMessage({
id: "rich-text.editor.toolbar.select.quote",
defaultMessage: "Quote",
})}
</Option>
<Option value={"orderedList"}>
{formatMessage({
id: "rich-text.editor.toolbar.select.ordered-list",
defaultMessage: "Ordered list",
})}
</Option>
<Option value={"bulletList"}>
{formatMessage({
id: "rich-text.editor.toolbar.select.bullet-list",
defaultMessage: "Bullet list",
})}
</Option>
</Select>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, { forwardRef, useCallback, useState } from "react";

import { createComponent, EventName } from "@lit/react";
import { Box } from "@strapi/design-system/Box";
import { Flex } from "@strapi/design-system/Flex";
import { IconButton } from "@strapi/design-system/IconButton";
import { Popover } from "@strapi/design-system/Popover";
import { Check } from "@strapi/icons";
import { Trash } from "@strapi/icons";

import { useIntl } from "react-intl";
import { HexColorPicker } from "vanilla-colorful/hex-color-picker.js";

const ColorPicker = createComponent({
react: React,
tagName: "hex-color-picker",
elementClass: HexColorPicker,
events: {
onEventColorChanged: "color-changed" as EventName<
CustomEvent<{ value: string }>
>,
},
});

type ColorPickerPopoverProps = {
color?: string;
onExit: () => void;
onRemove: () => void;
onChange: (color: string) => void;
};

const ColorPickerPopover = forwardRef<JSX.Element, ColorPickerPopoverProps>(
({ onExit, onRemove, color: currentColor, onChange }, ref) => {
const [color, setColor] = useState(currentColor);
const { formatMessage } = useIntl();

const onClose = useCallback(() => {
onExit();
}, []);

return (
<Popover
source={ref}
onDismiss={onClose}
placement="bottom"
spacing="8"
onPointerDownOutside={onClose}
>
{/* <Popover.Trigger>
<IconButton
icon={icon}
label={formatMessage({
id: label.id,
defaultMessage: label.defaultMessage,
})}
/>
</Popover.Trigger>
<Popover.Content>
</Popover.Content> */}
<Flex alignItems="start" gap={1}>
<Box>
<ColorPicker
color={color}
onEventColorChanged={(event) => setColor(event.detail.value)}
/>
</Box>
<Box>
<IconButton
icon={<Check />}
noBorder
label={formatMessage({
id: "rich-text.editor.dialog.button.change",
defaultMessage: "Change",
})}
onClick={() => {
if (!color) null;
else {
onChange(color);

onClose();
}
}}
/>
<IconButton
icon={<Trash />}
noBorder
label={formatMessage({
id: "rich-text.editor.dialog.button.remove",
defaultMessage: "Remove",
})}
onClick={() => {
onClose(), onRemove();
}}
/>
</Box>
</Flex>
</Popover>
);
}
);

export default ColorPickerPopover;
Loading