Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 30 additions & 7 deletions components/editor/SnippngCodeArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { addDoc, collection, doc, updateDoc } from "firebase/firestore";

const SnippngCodeArea = () => {
const editorRef = useRef<HTMLDivElement>(null); // useRef to persist existing ref. Might be useful when dealing with background image in future
const wrapperRef = useRef<HTMLDivElement>(null);
const [saving, setSaving] = useState(false);
const [updating, setUpdating] = useState(false);

Expand All @@ -53,6 +54,8 @@ const SnippngCodeArea = () => {
gradientAngle,
editorWidth,
uid,
bgImageVisiblePatch,
bgBlur,
} = editorConfig;

const saveSnippet = async () => {
Expand Down Expand Up @@ -108,23 +111,42 @@ const SnippngCodeArea = () => {
<NoSSRWrapper>
<div className="rounded-md bg-white dark:bg-zinc-900 md:p-8 p-4 flex justify-center border-[1px] flex-col items-center dark:border-zinc-500 border-zinc-200 shadow-md w-full">
<div className="w-full">
<SnippngControlHeader />
<SnippngControlHeader wrapperRef={wrapperRef} />
</div>
{bgImageVisiblePatch ? (
<button
className="dark:text-white text-zinc-900 ml-auto text-xs py-1 px-1.5 mb-1 hover:bg-zinc-100 dark:hover:bg-zinc-700"
onClick={() => {
handleConfigChange("bgImageVisiblePatch")(null);
}}
>
Remove bg image
</button>
) : null}
<div
id="code-wrapper"
ref={wrapperRef}
className={clsx(
"overflow-auto p-16 max-w-full",
"overflow-auto p-16 max-w-full relative",
editorWidth ? "w-fit" : "w-full"
)}
style={{
background: getEditorWrapperBg(
wrapperBg,
gradients,
gradientAngle
),
background: bgImageVisiblePatch
? "none"
: getEditorWrapperBg(wrapperBg, gradients, gradientAngle),
padding: `${paddingVertical}px ${paddingHorizontal}px`,
}}
>
{bgImageVisiblePatch ? (
<img
src={bgImageVisiblePatch}
alt="bg-image"
className="w-full h-full object-cover z-0 absolute inset-0"
style={{
filter: `blur(${bgBlur || 0}px)`,
}}
/>
) : null}
<div
ref={editorRef}
data-testid="editor-container"
Expand Down Expand Up @@ -238,6 +260,7 @@ const SnippngCodeArea = () => {
) : null}
</div>
</div>
{/* TODO: Add CTA to remove background image */}
</div>
{uid ? (
<small className="dark:text-zinc-300 text-left text-zinc-600 py-2 inline-block">
Expand Down
104 changes: 86 additions & 18 deletions components/editor/SnippngControlHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { useSnippngEditor } from "@/context/SnippngEditorContext";
import { useToast } from "@/context/ToastContext";
import { ColorPicker } from "@/lib/color-picker";
import { DOWNLOAD_OPTIONS, LANGUAGES, THEMES } from "@/lib/constants";
import {
defaultEditorConfig,
DOWNLOAD_OPTIONS,
LANGUAGES,
THEMES,
} from "@/lib/constants";
import { ImagePicker } from "@/lib/image-picker";
import { SelectOptionInterface } from "@/types";
import { getEditorWrapperBg } from "@/utils";
import { Menu, Transition } from "@headlessui/react";
Expand All @@ -11,16 +17,19 @@ import {
Cog6ToothIcon,
CommandLineIcon,
DocumentDuplicateIcon,
PhotoIcon,
SparklesIcon,
} from "@heroicons/react/24/outline";
import * as htmlToImage from "html-to-image";
import { Fragment } from "react";
import { Fragment, RefObject } from "react";
import Button from "../form/Button";
import Checkbox from "../form/Checkbox";
import Range from "../form/Range";
import Select from "../form/Select";

const SnippngControlHeader = () => {
const SnippngControlHeader: React.FC<{
wrapperRef: RefObject<HTMLDivElement>;
}> = ({ wrapperRef }) => {
const { editorConfig, handleConfigChange } = useSnippngEditor();
const { addToast } = useToast();

Expand All @@ -41,6 +50,8 @@ const SnippngControlHeader = () => {
gradients,
gradientAngle,
snippetsName,
bgBlur = 0,
bgImageVisiblePatch,
} = editorConfig;

const downloadImage = (type: SelectOptionInterface) => {
Expand Down Expand Up @@ -108,6 +119,22 @@ const SnippngControlHeader = () => {
data-testid="wrapper-color-picker"
className="relative lg:w-fit w-full flex lg:justify-start justify-end items-center gap-2"
>
<Button
onClick={() => {
if (!navigator?.clipboard)
return addToast({
message: "navigator unavailable",
type: "error",
});
navigator.clipboard?.writeText(code).then(() => {
addToast({
message: "Code snippet copied!",
});
});
}}
>
<DocumentDuplicateIcon className="h-5 w-5 dark:text-white text-zinc-900" />
</Button>
<ColorPicker
color={wrapperBg}
gradientColors={gradients}
Expand All @@ -134,22 +161,18 @@ const SnippngControlHeader = () => {
}}
></button>
</ColorPicker>
<Button
onClick={() => {
if (!navigator?.clipboard)
return addToast({
message: "navigator unavailable",
type: "error",
});
navigator.clipboard?.writeText(code).then(() => {
addToast({
message: "Code snippet copied!",
});
});
}}
<ImagePicker
aspect={
wrapperRef?.current
? wrapperRef.current.clientWidth / wrapperRef.current.clientHeight
: 1
}
onChange={(src) => handleConfigChange("bgImageVisiblePatch")(src)}
>
<DocumentDuplicateIcon className="h-5 w-5 dark:text-white text-zinc-900" />
</Button>
<button className="h-8 cursor-pointer rounded-sm outline justify-center items-center outline-1 dark:outline-white outline-zinc-400 flex aspect-square ">
<PhotoIcon className="h-4 w-4 mx-auto dark:text-white text-zinc-900" />
</button>
</ImagePicker>
</div>

<div className="ml-auto">
Expand Down Expand Up @@ -222,6 +245,51 @@ const SnippngControlHeader = () => {
}}
/>
</div>
<div className="py-1 px-2">
<Checkbox
label="Remove background"
id="remove-bg"
data-testid="remove-bg"
checked={
wrapperBg === "transparent" &&
!gradients.length &&
!bgBlur &&
!bgImageVisiblePatch
}
onChange={(e) => {
if (!e.target.checked) {
handleConfigChange("bgImageVisiblePatch")(
defaultEditorConfig.bgImageVisiblePatch
);
handleConfigChange("bgBlur")(defaultEditorConfig.bgBlur);
handleConfigChange("gradients")(
defaultEditorConfig.gradients
);
handleConfigChange("wrapperBg")(
defaultEditorConfig.wrapperBg
);
} else {
handleConfigChange("bgImageVisiblePatch")(null);
handleConfigChange("bgBlur")(0);
handleConfigChange("gradients")([]);
handleConfigChange("wrapperBg")("transparent");
}
}}
/>
</div>
<div className="py-1 px-2 z-30">
<Range
label={`Bg blur (${bgBlur}px)`}
value={bgBlur}
max={20}
min={0}
rangeMax="20"
rangeMin="0"
onChange={(e) => {
handleConfigChange("bgBlur")(+e.target.value);
}}
/>
</div>
<div className="py-1 px-2 z-30">
<Range
label={`Font size (${editorFontSize}px)`}
Expand Down
2 changes: 1 addition & 1 deletion components/form/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface Props extends React.InputHTMLAttributes<HTMLInputElement> {

const Input: React.FC<Props> = ({ label, containerClassName, ...props }) => {
return (
<div className="flex flex-col">
<div className={clsx("flex flex-col", containerClassName || "")}>
{label ? (
<label
className="text-sm my-0.5 dark:text-white text-zinc-900"
Expand Down
2 changes: 1 addition & 1 deletion components/form/Range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface Props extends React.InputHTMLAttributes<HTMLInputElement> {
}
const Range: React.FC<Props> = ({ rangeMax, rangeMin, label, ...props }) => {
return (
<div className="w-full my-2">
<div className="w-full my-2 dark:text-white text-zinc-900">
<div>
<p>{label}</p>
</div>
Expand Down
3 changes: 2 additions & 1 deletion components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import SnippngWindowControls from "./editor/SnippngWindowControls";
import ErrorText from "./ErrorText";
import Button from "./form/Button";
import Checkbox from "./form/Checkbox";
import Input from "./form/Input";
import Range from "./form/Range";
import Select from "./form/Select";
import Loader from "./Loader";
Expand All @@ -12,7 +13,6 @@ import NoSSRWrapper from "./NoSSRWrapper";
import SigninButton from "./SigninButton";
import ThemeToggle from "./ThemeToggle";
import Toast from "./Toast";

export {
Toast,
ThemeToggle,
Expand All @@ -28,4 +28,5 @@ export {
ErrorText,
SigninButton,
Loader,
Input,
};
6 changes: 3 additions & 3 deletions context/SnippngEditorContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ const SnippngContextProvider: React.FC<{ children: React.ReactNode }> = ({
key: K
) =>
(value: V) => {
setEditorConfig({
...editorConfig,
setEditorConfig((prevConfig) => ({
...prevConfig,
[key]: value,
});
}));
};

const handleLineHeight = useCallback(() => {
Expand Down
2 changes: 1 addition & 1 deletion lib/color-picker/components/ColorPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Input from "@/components/form/Input";
import { Input } from "@/components";
import { Menu, Transition } from "@headlessui/react";
import React, { Fragment, useCallback, useMemo } from "react";
import {
Expand Down
40 changes: 40 additions & 0 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,44 @@ export const DEFAULT_CODE_SNIPPET = `export const debounce = <F extends (...args
return debounced as (...args: Parameters<F>) => ReturnType<F>;
};`;

export const PEXELS_QUERY_STRINGS = [
"background",
"gradient",
"landscape",
"sky",
"night-sky",
"galaxy",
"coding",
"abstract",
"texture",
"beautiful-zoom-backgrounds",
"colors",
"rainbow",
"programming",
"gray",
"teal",
"blue",
"red",
"fruits",
"orange",
"shine",
"stars",
"green",
"food",
"coffee",
"ice",
"ocean",
"plane",
"seascapes",
"art",
"creative",
"summer",
"tea",
"water",
"juice",
"ice-cream",
];

export const defaultEditorConfig: SnippngEditorConfigInterface = {
code: DEFAULT_CODE_SNIPPET,
snippetsName: "",
Expand All @@ -479,6 +517,8 @@ export const defaultEditorConfig: SnippngEditorConfigInterface = {
gradients: ["#ba68c8", "#ffa7c4", "#e57373"],
gradientAngle: 140,
editorWidth: 0,
bgImageVisiblePatch: null,
bgBlur: 0,
};

export const DEFAULT_BASE_SETUP = {
Expand Down
Loading