bsign-customization-full 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bsign-customization-full",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite",
Binary file
Binary file
@@ -1,5 +1,6 @@
1
1
  import { type JSX, type ReactNode } from "react";
2
2
  import { ScrollArea } from "./ui/scroll-area";
3
+ import { resolveAssetUrl } from "../lib/asset-url";
3
4
 
4
5
  export default function ConstructureSidebar({ items, onSelectItem, children, selectedItem }: {
5
6
  items: Array<{
@@ -13,7 +14,7 @@ export default function ConstructureSidebar({ items, onSelectItem, children, sel
13
14
  return (
14
15
  <div className="flex h-full w-full flex-col border-b border-[#D6D6D6] md:flex-row md:border-r md:border-b-0">
15
16
  <div className="flex w-full items-center gap-3 overflow-x-auto border-b border-[#D6D6D6] bg-[#F4F4F4] p-3 md:h-full md:w-[110px] md:flex-col md:items-center md:gap-4 md:overflow-visible md:border-b-0 md:py-[15px] md:rounded-tl-3xl 2xl:w-[200px]">
16
- <img src="/logo.png" className="h-[30px] w-[74px] shrink-0 md:h-[37px] md:w-[92px]" />
17
+ <img src={resolveAssetUrl("/logo.png")} className="h-[30px] w-[74px] shrink-0 md:h-[37px] md:w-[92px]" />
17
18
  {items.map(item => {
18
19
  const Icon = item.icon;
19
20
  return (
@@ -7,9 +7,10 @@ import { Textarea } from "../ui/textarea"
7
7
  import { AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, ImageIcon, TypeIcon } from "lucide-react"
8
8
  import { ToggleGroup, ToggleGroupItem } from "../ui/toggle-group"
9
9
  import { useState } from "react"
10
- import { Checkbox } from "../ui/checkbox"
11
- import { Input } from "../ui/input"
10
+ import { Checkbox } from "../ui/checkbox"
11
+ import { Input } from "../ui/input"
12
12
  import { getMaxLineLengthByPt } from "../../lib/config-font"
13
+ import { resolveAssetUrl } from "../../lib/asset-url"
13
14
 
14
15
  export default function LayersContainer() {
15
16
  const { layers, init: setLayers, options } = useLayersStore()
@@ -94,11 +95,11 @@ export default function LayersContainer() {
94
95
  {layer.type === "image" && isImageLayer(layer) && (
95
96
  <div className="flex flex-col gap-4">
96
97
  <div className="flex items-center justify-center p-4 bg-slate-50 rounded-lg border-2 border-dashed border-slate-200">
97
- <img
98
- src={layer.props.imageSrc || "/placeholder.svg"}
99
- className={`h-16 max-w-full object-contain rounded shadow-sm`}
100
- alt="Layer preview"
101
- />
98
+ <img
99
+ src={layer.props.imageSrc || resolveAssetUrl("/placeholder.svg")}
100
+ className={`h-16 max-w-full object-contain rounded shadow-sm`}
101
+ alt="Layer preview"
102
+ />
102
103
  </div>
103
104
  </div>
104
105
  )}
@@ -3,9 +3,10 @@ import {
3
3
  DialogPortal,
4
4
  DialogOverlay,
5
5
  } from "./ui/dialog"
6
- import * as DialogPrimitive from "@radix-ui/react-dialog"
7
- import { cn } from "../lib/utils"
8
- import { X } from "lucide-react"
6
+ import * as DialogPrimitive from "@radix-ui/react-dialog"
7
+ import { cn } from "../lib/utils"
8
+ import { X } from "lucide-react"
9
+ import { resolveAssetUrl } from "../lib/asset-url"
9
10
 
10
11
  interface ImportFileModalProps {
11
12
  open: boolean
@@ -39,7 +40,7 @@ export function SizeGuideModal({
39
40
  Close
40
41
  </DialogPrimitive.Close>
41
42
  </div>
42
- <img src="/size-guide.webp" className="w-full h-auto rounded-2xl object-contain" />
43
+ <img src={resolveAssetUrl("/size-guide.webp")} className="w-full h-auto rounded-2xl object-contain" />
43
44
  </DialogPrimitive.Content>
44
45
  </DialogPortal>
45
46
  </Dialog>
package/src/index.css CHANGED
@@ -4,7 +4,7 @@
4
4
  @font-face {
5
5
  font-family: 'Bebasneue';
6
6
  src:
7
- url('https://cdn.jsdelivr.net/npm/bsign-customization@latest/src/fonts/BEBASNEUE-REGULAR.TTF') format('truetype');
7
+ url('/fonts/BEBASNEUE-REGULAR.TTF') format('truetype');
8
8
  font-weight: 400;
9
9
  font-style: normal;
10
10
  font-display: swap;
@@ -13,7 +13,7 @@
13
13
  @font-face {
14
14
  font-family: 'GOTHICB';
15
15
  src:
16
- url('./fonts/GOTHICB.TTF') format('truetype');
16
+ url('/fonts/GOTHICB.TTF') format('truetype');
17
17
  font-weight: 400;
18
18
  font-style: normal;
19
19
  font-display: swap;
@@ -22,11 +22,11 @@
22
22
  @font-face {
23
23
  font-family: 'Braille';
24
24
  src:
25
- url('https://cdn.jsdelivr.net/npm/bsign-customization@latest/src/fonts/Braille-Regular.ttf') format('truetype');
26
- font-weight: 400;
27
- font-style: normal;
28
- font-display: swap;
29
- }
25
+ url('/fonts/Braille-Regular.ttf') format('truetype');
26
+ font-weight: 400;
27
+ font-style: normal;
28
+ font-display: swap;
29
+ }
30
30
 
31
31
  @custom-variant dark (&:is(.dark *));
32
32
 
package/src/index.tsx CHANGED
@@ -3,6 +3,7 @@ import SignCustomizer, { type SignCustomizerProps } from "./AppDemo2"
3
3
  import resizableStyles from "react-resizable/css/styles.css?inline"
4
4
  import widgetStyles from "./index.css?inline"
5
5
  import { WidgetPortalContainerContext } from "./lib/widget-context"
6
+ import { resolveAssetUrl } from "./lib/asset-url"
6
7
 
7
8
  export type WidgetTarget = string | HTMLElement
8
9
 
@@ -10,7 +11,24 @@ export interface MountConstructorWidgetProps extends SignCustomizerProps {
10
11
  widgetCss?: string | string[]
11
12
  }
12
13
 
13
- const BASE_WIDGET_CSS = `${resizableStyles}\n${widgetStyles}`
14
+ const FONT_ASSET_PATHS = [
15
+ "/fonts/BEBASNEUE-REGULAR.TTF",
16
+ "/fonts/GOTHICB.TTF",
17
+ "/fonts/Braille-Regular.ttf",
18
+ ] as const
19
+
20
+ function resolveFontUrlsInCss(styles: string): string {
21
+ return FONT_ASSET_PATHS.reduce((nextStyles, fontPath) => {
22
+ const resolvedFontPath = resolveAssetUrl(fontPath)
23
+
24
+ return nextStyles
25
+ .replaceAll(`url('${fontPath}')`, `url('${resolvedFontPath}')`)
26
+ .replaceAll(`url("${fontPath}")`, `url("${resolvedFontPath}")`)
27
+ .replaceAll(`url(${fontPath})`, `url(${resolvedFontPath})`)
28
+ }, styles)
29
+ }
30
+
31
+ const BASE_WIDGET_CSS = `${resizableStyles}\n${resolveFontUrlsInCss(widgetStyles)}`
14
32
  const rootsByHost = new WeakMap<HTMLElement, Root>()
15
33
 
16
34
  function resolveTarget(target: WidgetTarget): HTMLElement {
@@ -0,0 +1,96 @@
1
+ const ABSOLUTE_URL_PATTERN = /^(?:[a-z][a-z\d+\-.]*:)?\/\//i
2
+ const SPECIAL_PROTOCOL_PATTERN = /^(?:data|blob):/i
3
+
4
+ function isLocalhostHost(hostname: string): boolean {
5
+ const normalizedHost = hostname.toLowerCase()
6
+ return (
7
+ normalizedHost === "localhost" ||
8
+ normalizedHost === "127.0.0.1" ||
9
+ normalizedHost === "[::1]" ||
10
+ normalizedHost.endsWith(".localhost")
11
+ )
12
+ }
13
+
14
+ function shouldUseRelativeUrls(): boolean {
15
+ if (typeof window === "undefined") {
16
+ return false
17
+ }
18
+
19
+ return isLocalhostHost(window.location.hostname)
20
+ }
21
+
22
+ function toBaseUrl(url: string): string | undefined {
23
+ try {
24
+ return new URL(".", url).toString()
25
+ } catch {
26
+ return undefined
27
+ }
28
+ }
29
+
30
+ function resolveDefaultAssetBaseUrl(): string {
31
+ const importMetaBase = toBaseUrl(import.meta.url)
32
+ if (importMetaBase) {
33
+ return importMetaBase
34
+ }
35
+
36
+ if (typeof document !== "undefined") {
37
+ const currentScript = document.currentScript
38
+ if (currentScript instanceof HTMLScriptElement && currentScript.src) {
39
+ const scriptBase = toBaseUrl(currentScript.src)
40
+ if (scriptBase) {
41
+ return scriptBase
42
+ }
43
+ }
44
+
45
+ const scripts = document.getElementsByTagName("script")
46
+ const lastScript = scripts.item(scripts.length - 1)
47
+ if (lastScript instanceof HTMLScriptElement && lastScript.src) {
48
+ const scriptBase = toBaseUrl(lastScript.src)
49
+ if (scriptBase) {
50
+ return scriptBase
51
+ }
52
+ }
53
+ }
54
+
55
+ if (typeof window !== "undefined") {
56
+ return toBaseUrl(window.location.href) ?? "/"
57
+ }
58
+
59
+ return "/"
60
+ }
61
+
62
+ let assetBaseUrl = resolveDefaultAssetBaseUrl()
63
+
64
+ export function setAssetBaseUrl(baseUrl?: string) {
65
+ if (!baseUrl) {
66
+ assetBaseUrl = resolveDefaultAssetBaseUrl()
67
+ return
68
+ }
69
+
70
+ assetBaseUrl = toBaseUrl(baseUrl) ?? assetBaseUrl
71
+ }
72
+
73
+ export function getAssetBaseUrl() {
74
+ return assetBaseUrl
75
+ }
76
+
77
+ export function resolveAssetUrl(path: string): string {
78
+ if (!path) {
79
+ return path
80
+ }
81
+
82
+ if (ABSOLUTE_URL_PATTERN.test(path) || SPECIAL_PROTOCOL_PATTERN.test(path)) {
83
+ return path
84
+ }
85
+
86
+ if (shouldUseRelativeUrls()) {
87
+ if (path.startsWith("/") || path.startsWith("./") || path.startsWith("../")) {
88
+ return path
89
+ }
90
+
91
+ return `./${path}`
92
+ }
93
+
94
+ const normalizedPath = path.startsWith("/") ? path.slice(1) : path
95
+ return new URL(normalizedPath, getAssetBaseUrl()).toString()
96
+ }
package/src/lib/config.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { LayrProps, TLayer } from "../components/preview";
2
2
  import { BASE_FONT_SIZE } from "./config-font";
3
+ import { resolveAssetUrl } from "./asset-url";
3
4
 
4
5
  export const prodApiUrl = "https://constructor-api-production.up.railway.app/v1/product/generate";
5
6
 
@@ -85,12 +86,12 @@ export const getSizeLimitScale = (size: Pick<TSize, "cm">): number => {
85
86
 
86
87
  const MODERN_BACKGROUND_ASSETS = {
87
88
  rectangle: {
88
- black: "/templates/assets/modern/rectangle-black.webp",
89
- white: "/templates/assets/modern/rectangle-white.webp",
89
+ black: resolveAssetUrl("/templates/assets/modern/rectangle-black.webp"),
90
+ white: resolveAssetUrl("/templates/assets/modern/rectangle-white.webp"),
90
91
  },
91
92
  square: {
92
- black: "/templates/assets/modern/square-black.webp",
93
- white: "/templates/assets/modern/square-white.webp",
93
+ black: resolveAssetUrl("/templates/assets/modern/square-black.webp"),
94
+ white: resolveAssetUrl("/templates/assets/modern/square-white.webp"),
94
95
  },
95
96
  } as const;
96
97
 
@@ -199,38 +200,38 @@ const WAVE_MATERIALS = [
199
200
  {
200
201
  id: "anthracite-gray",
201
202
  label: "Anthracite Gray",
202
- previewImage: "/colors/anthracite-gray_50x50.png",
203
- image: "/colors/anthracite-gray.webp",
203
+ previewImage: resolveAssetUrl("/colors/anthracite-gray_50x50.png"),
204
+ image: resolveAssetUrl("/colors/anthracite-gray.webp"),
204
205
  },
205
206
  {
206
207
  id: "indian-rosewood",
207
208
  label: "Indian Rosewood",
208
- previewImage: "/colors/indian-rosewood_50x50.png",
209
- image: "/colors/indian-rosewood.webp",
209
+ previewImage: resolveAssetUrl("/colors/indian-rosewood_50x50.png"),
210
+ image: resolveAssetUrl("/colors/indian-rosewood.webp"),
210
211
  },
211
212
  {
212
213
  id: "natural-wood",
213
214
  label: "Natural Wood",
214
- previewImage: "/colors/natural-wood_50x50.png",
215
- image: "/colors/natural-wood.webp",
215
+ previewImage: resolveAssetUrl("/colors/natural-wood_50x50.png"),
216
+ image: resolveAssetUrl("/colors/natural-wood.webp"),
216
217
  },
217
218
  {
218
219
  id: "walnut",
219
220
  label: "Walnut",
220
- previewImage: "/colors/walnut_50x50.png",
221
- image: "/colors/walnut.webp",
221
+ previewImage: resolveAssetUrl("/colors/walnut_50x50.png"),
222
+ image: resolveAssetUrl("/colors/walnut.webp"),
222
223
  },
223
224
  {
224
225
  id: "redwood",
225
226
  label: "Redwood",
226
- previewImage: "/colors/redwood_50x50.png",
227
- image: "/colors/redwood.webp",
227
+ previewImage: resolveAssetUrl("/colors/redwood_50x50.png"),
228
+ image: resolveAssetUrl("/colors/redwood.webp"),
228
229
  },
229
230
  {
230
231
  id: "dark-wenge",
231
232
  label: "Dark Wenge",
232
- previewImage: "/colors/dark-wenge_50x50.png",
233
- image: "/colors/dark-wenge.webp",
233
+ previewImage: resolveAssetUrl("/colors/dark-wenge_50x50.png"),
234
+ image: resolveAssetUrl("/colors/dark-wenge.webp"),
234
235
  },
235
236
  ] as const;
236
237
 
@@ -400,7 +401,7 @@ const modernTemplate: TemplateDefinition = {
400
401
  const waveTemplate: TemplateDefinition = {
401
402
  id: "wave",
402
403
  name: "Wave",
403
- image: "/templates/wave.webp",
404
+ image: resolveAssetUrl("/templates/wave.webp"),
404
405
  textFont: "font-bebasneue",
405
406
  defaultShapeId: "square",
406
407
  defaultMaterialId: "anthracite-gray",
@@ -410,7 +411,7 @@ const waveTemplate: TemplateDefinition = {
410
411
  id: "square",
411
412
  label: "Square",
412
413
  sizes: SQUARE_SIZES,
413
- previewImage: "/templates/wave.webp",
414
+ previewImage: resolveAssetUrl("/templates/wave.webp"),
414
415
  },
415
416
  ],
416
417
  materials: WAVE_MATERIALS.map((material) => ({
@@ -440,7 +441,7 @@ const waveTemplate: TemplateDefinition = {
440
441
  {
441
442
  type: "image",
442
443
  props: {
443
- imageSrc: "/templates/assets/wave.webp",
444
+ imageSrc: resolveAssetUrl("/templates/assets/wave.webp"),
444
445
  coordinates: {
445
446
  "3.5x3.5": { x: -35, y: 90 },
446
447
  "5x5": { x: -35, y: 100 },