feat: moved to shared-components and implemented focal point picker in RTE

This commit is contained in:
Erik Tiekstra
2024-10-15 11:15:58 +02:00
parent b1493bcd3d
commit 4c1ee66542
15 changed files with 246 additions and 27 deletions

177
package-lock.json generated
View File

@@ -34,6 +34,7 @@
"prettier": "^3.2.5", "prettier": "^3.2.5",
"typescript": "^5.1.6", "typescript": "^5.1.6",
"vite": "^5.1.0", "vite": "^5.1.0",
"vite-plugin-lib-inject-css": "^2.1.1",
"vite-tsconfig-paths": "^4.2.1" "vite-tsconfig-paths": "^4.2.1"
} }
}, },
@@ -74,6 +75,153 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@ast-grep/napi": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/@ast-grep/napi/-/napi-0.22.6.tgz",
"integrity": "sha512-kNF87HiI4omHC7VzyBZSvqOAXtMlSDRF2YX+O5ya0XKv/7/GYms1opLQ+BQ9twLLDj0WsSFX4MYg0TrinZTxTg==",
"dev": true,
"engines": {
"node": ">= 10"
},
"optionalDependencies": {
"@ast-grep/napi-darwin-arm64": "0.22.6",
"@ast-grep/napi-darwin-x64": "0.22.6",
"@ast-grep/napi-linux-arm64-gnu": "0.22.6",
"@ast-grep/napi-linux-x64-gnu": "0.22.6",
"@ast-grep/napi-linux-x64-musl": "0.22.6",
"@ast-grep/napi-win32-arm64-msvc": "0.22.6",
"@ast-grep/napi-win32-ia32-msvc": "0.22.6",
"@ast-grep/napi-win32-x64-msvc": "0.22.6"
}
},
"node_modules/@ast-grep/napi-darwin-arm64": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-arm64/-/napi-darwin-arm64-0.22.6.tgz",
"integrity": "sha512-L9rEGJ8fNi5LxbZj860wbXxjX7DLNV799zcTaPOSzYadvNyhMY3LWvDXd45Vtx6Dh8QRtCoEMQmw8KaRCEjm9A==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@ast-grep/napi-darwin-x64": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-x64/-/napi-darwin-x64-0.22.6.tgz",
"integrity": "sha512-0iuM6iDJNhcPd6a/JJr64AallR7ttGW/MvUujfQdvJEZY5p9LK35xm23dULznW0tIMgwtMKPRaprgk8LPondKg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@ast-grep/napi-linux-arm64-gnu": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-arm64-gnu/-/napi-linux-arm64-gnu-0.22.6.tgz",
"integrity": "sha512-9PAqNJlAQfFm1RW0DVCM/S4gFHdppxUTWacB3qEeJZXgdLnoH0KGQa4z3Xo559SPYDKZy0VnY02mZ3XJ+v6/Vw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@ast-grep/napi-linux-x64-gnu": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-gnu/-/napi-linux-x64-gnu-0.22.6.tgz",
"integrity": "sha512-nZf+gxXVrZqvP1LN6HwzOMA4brF3umBXfMequQzv8S6HeJ4c34P23F0Tw8mHtQpVYP9PQWJUvt3LJQ8Xvd5Hiw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@ast-grep/napi-linux-x64-musl": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-musl/-/napi-linux-x64-musl-0.22.6.tgz",
"integrity": "sha512-gcJeBMgJQf2pZZo0lgH0Vg4ycyujM7Am8VlomXhavC/dPpkddA1tiHSIC4fCNneLU1EqHITy3ALSmM4GLdsjBw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@ast-grep/napi-win32-arm64-msvc": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-arm64-msvc/-/napi-win32-arm64-msvc-0.22.6.tgz",
"integrity": "sha512-YDDzvPIyl4ti8xZfjvGSGVCX9JJjMQjyWPlXcwRpiLRnHThtHTDL8PyE2yq+gAPuZ28QbrygMkP9EKXIyYFVcQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@ast-grep/napi-win32-ia32-msvc": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-ia32-msvc/-/napi-win32-ia32-msvc-0.22.6.tgz",
"integrity": "sha512-w5P0MDcBD3bifC2K9nCDEFYacy8HQnXdf6fX6cIE/7xL8XEDs6D1lQjGewrZDcMAXVXUQfupj4P27ZsJRmuIoQ==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@ast-grep/napi-win32-x64-msvc": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-x64-msvc/-/napi-win32-x64-msvc-0.22.6.tgz",
"integrity": "sha512-1aaHvgsCBwUP0tDf4HXPMpUV/nUwsOWgRCiBc2zIJjdEjT9TTk795EIX9Z1Nc0OMCrxVEceyiKcYTofXa0Fpxw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.24.2", "version": "7.24.2",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz",
@@ -1902,9 +2050,9 @@
} }
}, },
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true "dev": true
}, },
"node_modules/@jridgewell/trace-mapping": { "node_modules/@jridgewell/trace-mapping": {
@@ -9589,6 +9737,15 @@
"node": "14 || >=16.14" "node": "14 || >=16.14"
} }
}, },
"node_modules/magic-string": {
"version": "0.30.12",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz",
"integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/make-array": { "node_modules/make-array": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz", "resolved": "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz",
@@ -14574,6 +14731,20 @@
"url": "https://opencollective.com/vitest" "url": "https://opencollective.com/vitest"
} }
}, },
"node_modules/vite-plugin-lib-inject-css": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/vite-plugin-lib-inject-css/-/vite-plugin-lib-inject-css-2.1.1.tgz",
"integrity": "sha512-RIMeVnqBK/8I0E9nnQWzws6pdj5ilRMPJSnXYb6nWxNR4EmDPnksnb/ACoR5Fy7QfzULqS4gtQMrjwnNCC9zoA==",
"dev": true,
"dependencies": {
"@ast-grep/napi": "^0.22.3",
"magic-string": "^0.30.10",
"picocolors": "^1.0.0"
},
"peerDependencies": {
"vite": "*"
}
},
"node_modules/vite-tsconfig-paths": { "node_modules/vite-tsconfig-paths": {
"version": "4.3.2", "version": "4.3.2",
"resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.3.2.tgz", "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.3.2.tgz",

View File

@@ -40,6 +40,7 @@
"prettier": "^3.2.5", "prettier": "^3.2.5",
"typescript": "^5.1.6", "typescript": "^5.1.6",
"vite": "^5.1.0", "vite": "^5.1.0",
"vite-plugin-lib-inject-css": "^2.1.1",
"vite-tsconfig-paths": "^4.2.1" "vite-tsconfig-paths": "^4.2.1"
} }
} }

View File

@@ -11,7 +11,7 @@ import {
} from "@contentstack/venus-components" } from "@contentstack/venus-components"
import type { FocalPoint, InsertResponse } from "~/types/imagevault" import type { FocalPoint, InsertResponse } from "~/types/imagevault"
import FocalPointPicker from "./FocalPointPicker" import FocalPointPicker from "~/shared-components/FocalPointPicker"
type ImageEditModalProps = { type ImageEditModalProps = {
fieldData: InsertResponse fieldData: InsertResponse
@@ -123,8 +123,7 @@ export default function ImageEditModal({
<FieldLabel htmlFor="focalPoint">Focal Point</FieldLabel> <FieldLabel htmlFor="focalPoint">Focal Point</FieldLabel>
<TextInput <TextInput
value={`X: ${focalPoint.x}, Y: ${focalPoint.y}`} value={`X: ${focalPoint.x}, Y: ${focalPoint.y}`}
placeholder="Caption for image..." name="focalPoint"
name="caption"
disabled disabled
/> />
</FieldComponent> </FieldComponent>

View File

@@ -6,7 +6,7 @@ import {
ScrollRestoration, ScrollRestoration,
useRouteError, useRouteError,
} from "@remix-run/react" } from "@remix-run/react"
import { SDKLoadingError } from "./hooks/useApp" import { SDKLoadingError } from "~/hooks/useApp"
export function Layout({ children }: { children: React.ReactNode }) { export function Layout({ children }: { children: React.ReactNode }) {
return ( return (

View File

@@ -4,6 +4,8 @@
"env.d.ts", "env.d.ts",
"../types/**/*.ts", "../types/**/*.ts",
"../utils/**/*.ts", "../utils/**/*.ts",
"../shared-components/**/*.ts",
"../shared-components/**/*.tsx",
"**/*.ts", "**/*.ts",
"**/*.tsx" "**/*.tsx"
], ],
@@ -15,7 +17,8 @@
"~/types/*": ["../types/*"], "~/types/*": ["../types/*"],
"~/utils/*": ["../utils/*"], "~/utils/*": ["../utils/*"],
"~/components/*": ["./app/components/*"], "~/components/*": ["./app/components/*"],
"~/hooks/*": ["./app/hooks/*"] "~/hooks/*": ["./app/hooks/*"],
"~/shared-components/*": ["../shared-components/*"],
} }
} }
} }

View File

@@ -16,7 +16,9 @@ import type {
IRteParam, IRteParam,
IRteElementType, IRteElementType,
} from "@contentstack/app-sdk/dist/src/RTE/types" } from "@contentstack/app-sdk/dist/src/RTE/types"
import type { InsertResponse } from "~/types/imagevault" import FocalPointPicker from "~/shared-components/FocalPointPicker"
import type { FocalPoint, InsertResponse } from "~/types/imagevault"
enum DropdownValues { enum DropdownValues {
center = "center", center = "center",
@@ -76,6 +78,7 @@ export default function ImageEditModal({
}) })
const [altText, setAltText] = useState("") const [altText, setAltText] = useState("")
const [caption, setCaption] = useState("") const [caption, setCaption] = useState("")
const [focalPoint, setFocalPoint] = useState<FocalPoint>({ x: 50, y: 50 })
const assetUrl = element.attrs.MediaConversions[0].Url const assetUrl = element.attrs.MediaConversions[0].Url
@@ -94,6 +97,12 @@ export default function ImageEditModal({
} }
}, [element.attrs.Metadata]) }, [element.attrs.Metadata])
useEffect(() => {
if (element.attrs.FocalPoint) {
setFocalPoint(element.attrs.FocalPoint)
}
}, [element.attrs.FocalPoint])
function handleSave() { function handleSave() {
let newStyle let newStyle
@@ -134,6 +143,7 @@ export default function ImageEditModal({
Metadata: newMetadata, Metadata: newMetadata,
position: alignment.value, position: alignment.value,
style: { ...element.attrs.style, ...newStyle }, style: { ...element.attrs.style, ...newStyle },
FocalPoint: focalPoint,
}, },
}, },
{ at: path } { at: path }
@@ -142,27 +152,29 @@ export default function ImageEditModal({
closeModal() closeModal()
} }
function changeFocalPoint(focalPoint: FocalPoint) {
setFocalPoint(focalPoint)
}
return ( return (
<> <>
<ModalHeader title="Update image" closeModal={closeModal} /> <ModalHeader title="Update image" closeModal={closeModal} />
<ModalBody <ModalBody
style={{ style={{
display: "flex", display: "grid",
gridTemplateColumns: "1fr minmax(max-content, 250px)",
gap: "1rem", gap: "1rem",
justifyContent: "space-between",
alignItems: "center", alignItems: "center",
width: "100%", width: "auto",
maxHeight: "none",
}} }}
> >
<div style={{ flex: 1, overflowY: "auto" }}> <FocalPointPicker
<img imageSrc={assetUrl}
src={assetUrl} focalPoint={focalPoint}
alt={altText} onChange={changeFocalPoint}
height="100%"
style={{ maxHeight: "345px" }}
/> />
</div> <div>
<div style={{ flex: 1 }}>
<Field> <Field>
<Select <Select
selectLabel="Alignment" selectLabel="Alignment"
@@ -196,6 +208,15 @@ export default function ImageEditModal({
} }
/> />
</Field> </Field>
<Field>
<FieldLabel htmlFor="focalPoint">Focal Point</FieldLabel>
<TextInput
value={`X: ${focalPoint.x}, Y: ${focalPoint.y}`}
name="focalPoint"
disabled
/>
</Field>
</div> </div>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>

View File

@@ -35,6 +35,13 @@ export function ImageElement({ children, element, rte }: ImageElementProps) {
}), }),
modalProps: { modalProps: {
size: "max", size: "max",
style: {
content: {
maxHeight: "90dvh",
width: "auto",
},
overlay: {},
},
}, },
}) })
}, [element, rte]) }, [element, rte])

View File

@@ -213,7 +213,10 @@ async function init() {
{ {
// @ts-expect-error: incorrect typings // @ts-expect-error: incorrect typings
type: "ImageVault", type: "ImageVault",
attrs: result, attrs: {
...result,
FocalPoint: result.FocalPoint || { x: 50, y: 50 },
},
uid: crypto.randomUUID(), uid: crypto.randomUUID(),
children: [{ text: "" }], children: [{ text: "" }],
}, },

View File

@@ -4,6 +4,8 @@
"env.d.ts", "env.d.ts",
"../types/**/*.ts", "../types/**/*.ts",
"../utils/**/*.ts", "../utils/**/*.ts",
"../shared-components/**/*.ts",
"../shared-components/**/*.tsx",
"**/*.ts", "**/*.ts",
"**/*.tsx" "**/*.tsx"
], ],
@@ -13,7 +15,8 @@
"paths": { "paths": {
"~/*": ["./*"], "~/*": ["./*"],
"~/types/*": ["../types/*"], "~/types/*": ["../types/*"],
"~/utils/*": ["../utils/*"] "~/utils/*": ["../utils/*"],
"~/shared-components/*": ["../shared-components/*"],
} }
} }
} }

View File

@@ -1,9 +1,10 @@
import { resolve } from "path" import { resolve } from "path"
import { defineConfig } from "vite" import { defineConfig } from "vite"
import tsconfigPaths from "vite-tsconfig-paths" import tsconfigPaths from "vite-tsconfig-paths"
import { libInjectCss } from "vite-plugin-lib-inject-css"
export default defineConfig({ export default defineConfig({
plugins: [tsconfigPaths()], plugins: [tsconfigPaths(), libInjectCss()],
define: { define: {
IS_DEV: process.env.IS_DEV === "true" ? true : false, IS_DEV: process.env.IS_DEV === "true" ? true : false,
}, },

View File

@@ -1,6 +1,9 @@
import { FocalPoint } from "~/types/imagevault" import React from "react"
import useFocalPoint from "./useFocalPoint"
import type { FocalPoint } from "~/types/imagevault"
import "./focalPointPicker.css" import "./focalPointPicker.css"
import useFocalPoint from "~/hooks/useFocalPoint"
export interface FocalPointPickerProps { export interface FocalPointPickerProps {
focalPoint?: FocalPoint focalPoint?: FocalPoint

View File

@@ -11,6 +11,13 @@
"allowJs": true, "allowJs": true,
"skipLibCheck": true, "skipLibCheck": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"noEmit": true "noEmit": true,
"jsx": "react",
"baseUrl": ".",
"paths": {
"~/types/*": ["./types/*"],
"~/utils/*": ["./utils/*"],
"~/shared-components/*": ["./shared-components/*"],
}
} }
} }