@yoamigo.com/core 0.1.0
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/LICENSE +11 -0
- package/README.md +81 -0
- package/dist/MarkdownText-mylt-QX-.d.ts +106 -0
- package/dist/api-client-D8FkeBAI.d.ts +40 -0
- package/dist/asset-resolver-BnIvDkVv.d.ts +72 -0
- package/dist/builder-selection-CYP91nRu.d.ts +6 -0
- package/dist/index.css +372 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.js +2579 -0
- package/dist/lib-prod.d.ts +13 -0
- package/dist/lib-prod.js +108 -0
- package/dist/lib.d.ts +84 -0
- package/dist/lib.js +736 -0
- package/dist/plugin.d.ts +47 -0
- package/dist/plugin.js +96 -0
- package/dist/prod.d.ts +31 -0
- package/dist/prod.js +295 -0
- package/dist/router.d.ts +46 -0
- package/dist/router.js +42 -0
- package/package.json +115 -0
- package/src/styles/index.css +5 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Copyright (c) 2025 YoAmigo. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
This software and associated documentation files (the "Software") are the
|
|
4
|
+
proprietary property of YoAmigo. Unauthorized copying, modification,
|
|
5
|
+
distribution, or use of this Software, via any medium, is strictly prohibited.
|
|
6
|
+
|
|
7
|
+
The Software is provided for use solely in connection with the YoAmigo platform
|
|
8
|
+
and template development program. Any other use requires explicit written
|
|
9
|
+
permission from YoAmigo.
|
|
10
|
+
|
|
11
|
+
For licensing inquiries, contact: support@yoamigo.com
|
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# @yoamigo/core
|
|
2
|
+
|
|
3
|
+
Core components, Vite plugin, and utilities for building YoAmigo templates.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @yoamigo/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Vite Plugin
|
|
14
|
+
|
|
15
|
+
Add the YoAmigo plugin to your `vite.config.ts`:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { defineConfig } from 'vite'
|
|
19
|
+
import { yoamigoPlugin } from '@yoamigo/core/plugin'
|
|
20
|
+
|
|
21
|
+
export default defineConfig({
|
|
22
|
+
plugins: [yoamigoPlugin()],
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The plugin automatically handles:
|
|
27
|
+
- React/Preact swap in production builds
|
|
28
|
+
- Path aliases (`@/` maps to `src/`)
|
|
29
|
+
- Environment variables (`YA_*` prefix)
|
|
30
|
+
- Optimized build output
|
|
31
|
+
|
|
32
|
+
### Components
|
|
33
|
+
|
|
34
|
+
Use the editable components in your templates:
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { YaText, YaImage, YaLink, ContentStoreProvider } from '@yoamigo/core'
|
|
38
|
+
|
|
39
|
+
function App() {
|
|
40
|
+
return (
|
|
41
|
+
<ContentStoreProvider>
|
|
42
|
+
<h1>
|
|
43
|
+
<YaText fieldId="hero.title" />
|
|
44
|
+
</h1>
|
|
45
|
+
<YaImage fieldId="hero.image" className="hero-img" />
|
|
46
|
+
<YaLink fieldId="hero.cta" className="btn">
|
|
47
|
+
<YaText fieldId="hero.cta.text" />
|
|
48
|
+
</YaLink>
|
|
49
|
+
</ContentStoreProvider>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Router
|
|
55
|
+
|
|
56
|
+
A lightweight router for multi-page templates:
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { Router, Route, Link, useLocation } from '@yoamigo/core/router'
|
|
60
|
+
|
|
61
|
+
function App() {
|
|
62
|
+
return (
|
|
63
|
+
<Router>
|
|
64
|
+
<nav>
|
|
65
|
+
<Link href="/">Home</Link>
|
|
66
|
+
<Link href="/about">About</Link>
|
|
67
|
+
</nav>
|
|
68
|
+
<Route path="/" component={Home} />
|
|
69
|
+
<Route path="/about" component={About} />
|
|
70
|
+
</Router>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Documentation
|
|
76
|
+
|
|
77
|
+
For full documentation, visit [yoamigo.com/developers](https://yoamigo.com/developers).
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
Proprietary - All Rights Reserved. See LICENSE file for details.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React$1, { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type EditMode = 'read-only' | 'inline-edit';
|
|
5
|
+
interface ContentStore {
|
|
6
|
+
getValue: (fieldId: string) => string;
|
|
7
|
+
setValue: (fieldId: string, value: string) => void;
|
|
8
|
+
mode: EditMode;
|
|
9
|
+
setMode: (mode: EditMode) => void;
|
|
10
|
+
subscribe: (listener: () => void) => () => void;
|
|
11
|
+
saveToWorker?: (fieldId: string, value: string) => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
declare function useContentStore(): ContentStore;
|
|
14
|
+
interface ContentStoreProviderProps {
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
initialContent?: Record<string, string>;
|
|
17
|
+
initialMode?: EditMode;
|
|
18
|
+
}
|
|
19
|
+
declare function ContentStoreProvider({ children }: ContentStoreProviderProps): react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
interface PageInfo {
|
|
22
|
+
path: string;
|
|
23
|
+
label: string;
|
|
24
|
+
}
|
|
25
|
+
interface YaLinkProps {
|
|
26
|
+
fieldId: string;
|
|
27
|
+
/** Default href if not set in content store */
|
|
28
|
+
href?: string;
|
|
29
|
+
className?: string;
|
|
30
|
+
as?: 'a' | 'span';
|
|
31
|
+
children?: React$1.ReactNode;
|
|
32
|
+
/** Available pages for href dropdown (injected by template) */
|
|
33
|
+
availablePages?: PageInfo[];
|
|
34
|
+
/** Optional click handler called after navigation */
|
|
35
|
+
onClick?: () => void;
|
|
36
|
+
}
|
|
37
|
+
declare module '@tiptap/core' {
|
|
38
|
+
interface Commands<ReturnType> {
|
|
39
|
+
fontSize: {
|
|
40
|
+
setFontSize: (fontSize: string) => ReturnType;
|
|
41
|
+
unsetFontSize: () => ReturnType;
|
|
42
|
+
};
|
|
43
|
+
fontWeight: {
|
|
44
|
+
setFontWeight: (fontWeight: string) => ReturnType;
|
|
45
|
+
unsetFontWeight: () => ReturnType;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
declare function YaLink({ fieldId, href: defaultHref, className, as: Component, children, availablePages, onClick }: YaLinkProps): react_jsx_runtime.JSX.Element;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* StaticText Component - Production-only static text renderer
|
|
53
|
+
*
|
|
54
|
+
* This component replaces MpText in production builds via Vite alias.
|
|
55
|
+
* No editing capabilities, no Tiptap, no DOMPurify - minimal bundle size.
|
|
56
|
+
*
|
|
57
|
+
* Content from content.json is trusted because:
|
|
58
|
+
* 1. It's created in the builder using Tiptap (which controls allowed markup)
|
|
59
|
+
* 2. It's sanitized by SafeHtml when displayed in the builder
|
|
60
|
+
* 3. Users can't inject arbitrary HTML
|
|
61
|
+
*/
|
|
62
|
+
/** Common HTML elements that MpText can render as */
|
|
63
|
+
type MpTextElement = 'span' | 'div' | 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'strong' | 'em';
|
|
64
|
+
interface MpTextProps {
|
|
65
|
+
fieldId: string;
|
|
66
|
+
className?: string;
|
|
67
|
+
as?: MpTextElement;
|
|
68
|
+
/** Optional fallback content (used if fieldId not in store) */
|
|
69
|
+
children?: React.ReactNode;
|
|
70
|
+
}
|
|
71
|
+
declare function MpText({ fieldId, className, as: Component, children }: MpTextProps): react_jsx_runtime.JSX.Element;
|
|
72
|
+
|
|
73
|
+
type StaticTextProps = MpTextProps;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* StaticImage Component - Production-only static image renderer
|
|
77
|
+
*
|
|
78
|
+
* This component replaces MpImage in production builds via Vite alias.
|
|
79
|
+
* No editing overlay, no click handlers, no postMessage - minimal bundle size.
|
|
80
|
+
*/
|
|
81
|
+
interface MpImageProps {
|
|
82
|
+
fieldId: string;
|
|
83
|
+
className?: string;
|
|
84
|
+
alt?: string;
|
|
85
|
+
objectFit?: 'cover' | 'contain' | 'fill';
|
|
86
|
+
objectPosition?: string;
|
|
87
|
+
loading?: 'lazy' | 'eager';
|
|
88
|
+
/** Fallback for backward compatibility with config.ts images */
|
|
89
|
+
fallbackSrc?: string;
|
|
90
|
+
/** Fallback alt text */
|
|
91
|
+
fallbackAlt?: string;
|
|
92
|
+
}
|
|
93
|
+
declare function MpImage({ fieldId, className, alt, objectFit: propObjectFit, objectPosition: propObjectPosition, loading, fallbackSrc, fallbackAlt, }: MpImageProps): react_jsx_runtime.JSX.Element;
|
|
94
|
+
|
|
95
|
+
type StaticImageProps = MpImageProps;
|
|
96
|
+
|
|
97
|
+
interface MarkdownTextProps {
|
|
98
|
+
content: string;
|
|
99
|
+
className?: string;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* MarkdownText component - renders markdown content safely
|
|
103
|
+
*/
|
|
104
|
+
declare function MarkdownText({ content, className }: MarkdownTextProps): react_jsx_runtime.JSX.Element;
|
|
105
|
+
|
|
106
|
+
export { ContentStoreProvider as C, type EditMode as E, MpText as M, type PageInfo as P, type StaticTextProps as S, YaLink as Y, type ContentStore as a, MpImage as b, type StaticImageProps as c, MarkdownText as d, type MarkdownTextProps as e, type YaLinkProps as f, useContentStore as u };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Client
|
|
3
|
+
*
|
|
4
|
+
* Handles communication with the backend API for:
|
|
5
|
+
* - Email subscriptions
|
|
6
|
+
* - Contact form submissions
|
|
7
|
+
* - Product/cart operations (future)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Subscribe to newsletter
|
|
11
|
+
*/
|
|
12
|
+
declare function subscribeToNewsletter(email: string): Promise<{
|
|
13
|
+
success: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* Submit contact form
|
|
17
|
+
*/
|
|
18
|
+
interface ContactFormData {
|
|
19
|
+
name: string;
|
|
20
|
+
email: string;
|
|
21
|
+
phone?: string;
|
|
22
|
+
eventType?: string;
|
|
23
|
+
eventDate?: string;
|
|
24
|
+
location?: string;
|
|
25
|
+
message: string;
|
|
26
|
+
}
|
|
27
|
+
declare function submitContactForm(data: ContactFormData): Promise<{
|
|
28
|
+
success: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Get site metadata (used by worker for runtime config injection)
|
|
32
|
+
*/
|
|
33
|
+
interface SiteMetadata {
|
|
34
|
+
siteId: string;
|
|
35
|
+
apiUrl: string;
|
|
36
|
+
version: number;
|
|
37
|
+
}
|
|
38
|
+
declare function getSiteMetadata(): Promise<SiteMetadata | null>;
|
|
39
|
+
|
|
40
|
+
export { type ContactFormData as C, type SiteMetadata as S, submitContactForm as a, getSiteMetadata as g, subscribeToNewsletter as s };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Registry - Global content store for production builds
|
|
3
|
+
*
|
|
4
|
+
* Templates register their content.json at startup, and StaticText/StaticImage
|
|
5
|
+
* components read from this registry instead of importing directly.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // In template's main.tsx:
|
|
9
|
+
* import content from './content.json'
|
|
10
|
+
* import { registerContent } from '@yoamigo/template-base'
|
|
11
|
+
* registerContent(content)
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Register content from template's content.json
|
|
15
|
+
* Call this at app startup before rendering
|
|
16
|
+
*/
|
|
17
|
+
declare function registerContent(content: Record<string, string>): void;
|
|
18
|
+
/**
|
|
19
|
+
* Get content value by fieldId
|
|
20
|
+
* @param fieldId - Dot-notation path (e.g., 'hero.title', 'artist.bio')
|
|
21
|
+
* @returns The content string, or empty string if not found
|
|
22
|
+
*/
|
|
23
|
+
declare function getContent(fieldId: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Get all content as a Record
|
|
26
|
+
* Useful for initializing ContentStoreProvider
|
|
27
|
+
*/
|
|
28
|
+
declare function getAllContent(): Record<string, string>;
|
|
29
|
+
/**
|
|
30
|
+
* Check if a fieldId exists in content
|
|
31
|
+
*/
|
|
32
|
+
declare function hasContent(fieldId: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Content registry interface for type exports
|
|
35
|
+
*/
|
|
36
|
+
interface ContentRegistry {
|
|
37
|
+
registerContent: typeof registerContent;
|
|
38
|
+
getContent: typeof getContent;
|
|
39
|
+
getAllContent: typeof getAllContent;
|
|
40
|
+
hasContent: typeof hasContent;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Content registry object for convenience
|
|
44
|
+
*/
|
|
45
|
+
declare const contentRegistry: ContentRegistry;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Asset Resolver - Configurable asset URL resolution
|
|
49
|
+
*
|
|
50
|
+
* Templates register their asset resolver at startup. This allows
|
|
51
|
+
* MpImage/StaticImage to resolve asset paths correctly based on
|
|
52
|
+
* Vite's base path configuration.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* // In template's main.tsx:
|
|
56
|
+
* import { setAssetResolver } from '@yoamigo/template-base'
|
|
57
|
+
* setAssetResolver((path) => `${import.meta.env.BASE_URL}${path}`)
|
|
58
|
+
*/
|
|
59
|
+
type AssetResolverFn = (path: string) => string;
|
|
60
|
+
type AssetResolver = AssetResolverFn;
|
|
61
|
+
/**
|
|
62
|
+
* Set the asset resolver function
|
|
63
|
+
* Call this at app startup before rendering
|
|
64
|
+
*/
|
|
65
|
+
declare function setAssetResolver(resolver: AssetResolver): void;
|
|
66
|
+
/**
|
|
67
|
+
* Resolve an asset path to a full URL
|
|
68
|
+
* Uses the registered resolver function
|
|
69
|
+
*/
|
|
70
|
+
declare function resolveAssetUrl(path: string): string;
|
|
71
|
+
|
|
72
|
+
export { type AssetResolverFn as A, type ContentRegistry as C, getAllContent as a, resolveAssetUrl as b, contentRegistry as c, getContent as g, hasContent as h, registerContent as r, setAssetResolver as s };
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/* src/components/ya-tooltip.css */
|
|
2
|
+
.ya-tooltip {
|
|
3
|
+
position: fixed;
|
|
4
|
+
z-index: 9999;
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
gap: 6px;
|
|
8
|
+
padding: 8px 12px;
|
|
9
|
+
background: #1a1a1a;
|
|
10
|
+
color: white;
|
|
11
|
+
border-radius: 6px;
|
|
12
|
+
font-size: 13px;
|
|
13
|
+
font-weight: 500;
|
|
14
|
+
font-family:
|
|
15
|
+
system-ui,
|
|
16
|
+
-apple-system,
|
|
17
|
+
BlinkMacSystemFont,
|
|
18
|
+
"Segoe UI",
|
|
19
|
+
sans-serif;
|
|
20
|
+
white-space: nowrap;
|
|
21
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
22
|
+
animation: ya-tooltip-fade-in 0.15s ease;
|
|
23
|
+
pointer-events: none;
|
|
24
|
+
}
|
|
25
|
+
@keyframes ya-tooltip-fade-in {
|
|
26
|
+
from {
|
|
27
|
+
opacity: 0;
|
|
28
|
+
transform: scale(0.95);
|
|
29
|
+
}
|
|
30
|
+
to {
|
|
31
|
+
opacity: 1;
|
|
32
|
+
transform: scale(1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
.ya-tooltip svg {
|
|
36
|
+
width: 16px;
|
|
37
|
+
height: 16px;
|
|
38
|
+
flex-shrink: 0;
|
|
39
|
+
}
|
|
40
|
+
.ya-tooltip-bottom {
|
|
41
|
+
transform: translateX(-50%);
|
|
42
|
+
}
|
|
43
|
+
.ya-tooltip-bottom::before {
|
|
44
|
+
content: "";
|
|
45
|
+
position: absolute;
|
|
46
|
+
bottom: 100%;
|
|
47
|
+
left: 50%;
|
|
48
|
+
transform: translateX(-50%);
|
|
49
|
+
border: 6px solid transparent;
|
|
50
|
+
border-bottom-color: #1a1a1a;
|
|
51
|
+
}
|
|
52
|
+
.ya-tooltip-top {
|
|
53
|
+
transform: translateX(-50%);
|
|
54
|
+
}
|
|
55
|
+
.ya-tooltip-top::before {
|
|
56
|
+
content: "";
|
|
57
|
+
position: absolute;
|
|
58
|
+
top: 100%;
|
|
59
|
+
left: 50%;
|
|
60
|
+
transform: translateX(-50%);
|
|
61
|
+
border: 6px solid transparent;
|
|
62
|
+
border-top-color: #1a1a1a;
|
|
63
|
+
}
|
|
64
|
+
.ya-tooltip-right {
|
|
65
|
+
transform: translateY(-50%);
|
|
66
|
+
}
|
|
67
|
+
.ya-tooltip-right::before {
|
|
68
|
+
content: "";
|
|
69
|
+
position: absolute;
|
|
70
|
+
right: 100%;
|
|
71
|
+
top: 50%;
|
|
72
|
+
transform: translateY(-50%);
|
|
73
|
+
border: 6px solid transparent;
|
|
74
|
+
border-right-color: #1a1a1a;
|
|
75
|
+
}
|
|
76
|
+
.ya-tooltip-left {
|
|
77
|
+
transform: translateY(-50%);
|
|
78
|
+
}
|
|
79
|
+
.ya-tooltip-left::before {
|
|
80
|
+
content: "";
|
|
81
|
+
position: absolute;
|
|
82
|
+
left: 100%;
|
|
83
|
+
top: 50%;
|
|
84
|
+
transform: translateY(-50%);
|
|
85
|
+
border: 6px solid transparent;
|
|
86
|
+
border-left-color: #1a1a1a;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* src/components/ya-link.css */
|
|
90
|
+
.ya-link-wrapper {
|
|
91
|
+
position: relative;
|
|
92
|
+
display: inline;
|
|
93
|
+
}
|
|
94
|
+
.ya-link-editable {
|
|
95
|
+
cursor: pointer;
|
|
96
|
+
transition: outline 0.15s ease;
|
|
97
|
+
}
|
|
98
|
+
.ya-link-editable:hover {
|
|
99
|
+
outline: 2px dashed var(--color-primary, #D4A574);
|
|
100
|
+
outline-offset: 4px;
|
|
101
|
+
border-radius: 4px;
|
|
102
|
+
}
|
|
103
|
+
body.builder-selector-active .ya-link-editable:hover {
|
|
104
|
+
outline: none;
|
|
105
|
+
cursor: inherit;
|
|
106
|
+
}
|
|
107
|
+
.ya-link-editing {
|
|
108
|
+
outline: 2px solid var(--color-primary, #D4A574);
|
|
109
|
+
outline-offset: 4px;
|
|
110
|
+
border-radius: 4px;
|
|
111
|
+
position: relative;
|
|
112
|
+
}
|
|
113
|
+
.ya-link-actions {
|
|
114
|
+
display: flex;
|
|
115
|
+
gap: 8px;
|
|
116
|
+
position: absolute;
|
|
117
|
+
bottom: -60px;
|
|
118
|
+
right: 0;
|
|
119
|
+
z-index: 10;
|
|
120
|
+
background: rgba(26, 26, 26, 0.95);
|
|
121
|
+
padding: 8px 10px;
|
|
122
|
+
border-radius: 8px;
|
|
123
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
|
124
|
+
font-family:
|
|
125
|
+
system-ui,
|
|
126
|
+
-apple-system,
|
|
127
|
+
BlinkMacSystemFont,
|
|
128
|
+
"Segoe UI",
|
|
129
|
+
sans-serif;
|
|
130
|
+
}
|
|
131
|
+
.ya-link-btn {
|
|
132
|
+
padding: 6px 14px;
|
|
133
|
+
font-size: 12px;
|
|
134
|
+
font-weight: 500;
|
|
135
|
+
border-radius: 6px;
|
|
136
|
+
cursor: pointer;
|
|
137
|
+
transition: all 0.15s ease;
|
|
138
|
+
border: none;
|
|
139
|
+
}
|
|
140
|
+
.ya-link-btn-cancel {
|
|
141
|
+
background: #333333;
|
|
142
|
+
color: #ffffff;
|
|
143
|
+
border: 1px solid #555555;
|
|
144
|
+
}
|
|
145
|
+
.ya-link-btn-cancel:hover {
|
|
146
|
+
background: #444444;
|
|
147
|
+
color: #ffffff;
|
|
148
|
+
border-color: #666666;
|
|
149
|
+
}
|
|
150
|
+
.ya-link-btn-save {
|
|
151
|
+
background: #D4A574;
|
|
152
|
+
color: #1a1a1a;
|
|
153
|
+
}
|
|
154
|
+
.ya-link-btn-save:hover {
|
|
155
|
+
background: #c4956a;
|
|
156
|
+
}
|
|
157
|
+
.ya-href-popover {
|
|
158
|
+
position: absolute;
|
|
159
|
+
top: 100%;
|
|
160
|
+
left: 50%;
|
|
161
|
+
margin-top: 8px;
|
|
162
|
+
z-index: 10;
|
|
163
|
+
min-width: 280px;
|
|
164
|
+
max-width: 320px;
|
|
165
|
+
background: #1a1a1a;
|
|
166
|
+
border-radius: 12px;
|
|
167
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
|
168
|
+
transform: translateX(-50%);
|
|
169
|
+
animation: ya-href-popover-fade-in 0.15s ease;
|
|
170
|
+
overflow: hidden;
|
|
171
|
+
font-family:
|
|
172
|
+
system-ui,
|
|
173
|
+
-apple-system,
|
|
174
|
+
BlinkMacSystemFont,
|
|
175
|
+
"Segoe UI",
|
|
176
|
+
sans-serif;
|
|
177
|
+
}
|
|
178
|
+
@keyframes ya-href-popover-fade-in {
|
|
179
|
+
from {
|
|
180
|
+
opacity: 0;
|
|
181
|
+
transform: translateX(-50%) translateY(-8px);
|
|
182
|
+
}
|
|
183
|
+
to {
|
|
184
|
+
opacity: 1;
|
|
185
|
+
transform: translateX(-50%) translateY(0);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
.ya-href-popover::before {
|
|
189
|
+
content: "";
|
|
190
|
+
position: absolute;
|
|
191
|
+
top: -6px;
|
|
192
|
+
left: 50%;
|
|
193
|
+
transform: translateX(-50%);
|
|
194
|
+
border-left: 8px solid transparent;
|
|
195
|
+
border-right: 8px solid transparent;
|
|
196
|
+
border-bottom: 8px solid #1a1a1a;
|
|
197
|
+
}
|
|
198
|
+
.ya-href-popover-header {
|
|
199
|
+
padding: 12px 16px;
|
|
200
|
+
font-size: 13px;
|
|
201
|
+
font-weight: 600;
|
|
202
|
+
color: #ffffff;
|
|
203
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
204
|
+
}
|
|
205
|
+
.ya-href-popover-section {
|
|
206
|
+
padding: 12px 16px;
|
|
207
|
+
}
|
|
208
|
+
.ya-href-popover-label {
|
|
209
|
+
display: block;
|
|
210
|
+
font-size: 11px;
|
|
211
|
+
font-weight: 500;
|
|
212
|
+
color: rgba(255, 255, 255, 0.6);
|
|
213
|
+
text-transform: uppercase;
|
|
214
|
+
letter-spacing: 0.5px;
|
|
215
|
+
margin-bottom: 8px;
|
|
216
|
+
}
|
|
217
|
+
.ya-href-collapsible-header {
|
|
218
|
+
display: flex;
|
|
219
|
+
align-items: center;
|
|
220
|
+
gap: 6px;
|
|
221
|
+
width: 100%;
|
|
222
|
+
padding: 0;
|
|
223
|
+
background: transparent;
|
|
224
|
+
border: none;
|
|
225
|
+
cursor: pointer;
|
|
226
|
+
transition: color 0.15s ease;
|
|
227
|
+
}
|
|
228
|
+
.ya-href-collapsible-header:hover {
|
|
229
|
+
color: rgba(255, 255, 255, 0.8);
|
|
230
|
+
}
|
|
231
|
+
.ya-href-chevron {
|
|
232
|
+
font-size: 8px;
|
|
233
|
+
color: rgba(255, 255, 255, 0.4);
|
|
234
|
+
}
|
|
235
|
+
.ya-href-popover-pages {
|
|
236
|
+
display: flex;
|
|
237
|
+
flex-direction: column;
|
|
238
|
+
gap: 4px;
|
|
239
|
+
max-height: 200px;
|
|
240
|
+
overflow-y: auto;
|
|
241
|
+
}
|
|
242
|
+
.ya-href-page-btn {
|
|
243
|
+
display: flex;
|
|
244
|
+
flex-direction: column;
|
|
245
|
+
align-items: flex-start;
|
|
246
|
+
gap: 4px;
|
|
247
|
+
width: 100%;
|
|
248
|
+
padding: 10px 12px;
|
|
249
|
+
background: rgba(255, 255, 255, 0.05);
|
|
250
|
+
border: 1px solid transparent;
|
|
251
|
+
border-radius: 8px;
|
|
252
|
+
color: #e0e0e0;
|
|
253
|
+
font-size: 13px;
|
|
254
|
+
font-weight: 500;
|
|
255
|
+
text-align: left;
|
|
256
|
+
cursor: pointer;
|
|
257
|
+
transition: all 0.15s ease;
|
|
258
|
+
}
|
|
259
|
+
.ya-href-page-btn:hover {
|
|
260
|
+
background: rgba(255, 255, 255, 0.1);
|
|
261
|
+
border-color: rgba(255, 255, 255, 0.2);
|
|
262
|
+
}
|
|
263
|
+
.ya-href-page-btn.is-selected {
|
|
264
|
+
background: #D4A574;
|
|
265
|
+
color: #1a1a1a;
|
|
266
|
+
}
|
|
267
|
+
.ya-href-page-btn.is-selected .ya-href-page-path {
|
|
268
|
+
color: rgba(26, 26, 26, 0.6);
|
|
269
|
+
}
|
|
270
|
+
.ya-href-page-path {
|
|
271
|
+
font-size: 11px;
|
|
272
|
+
color: rgba(255, 255, 255, 0.4);
|
|
273
|
+
font-family: monospace;
|
|
274
|
+
word-break: break-all;
|
|
275
|
+
}
|
|
276
|
+
.ya-href-external-toggle {
|
|
277
|
+
display: block;
|
|
278
|
+
width: 100%;
|
|
279
|
+
padding: 10px 16px;
|
|
280
|
+
background: transparent;
|
|
281
|
+
border: none;
|
|
282
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
283
|
+
color: #D4A574;
|
|
284
|
+
font-size: 12px;
|
|
285
|
+
font-weight: 500;
|
|
286
|
+
text-align: center;
|
|
287
|
+
cursor: pointer;
|
|
288
|
+
transition: background 0.15s ease;
|
|
289
|
+
}
|
|
290
|
+
.ya-href-external-toggle:hover {
|
|
291
|
+
background: rgba(255, 255, 255, 0.05);
|
|
292
|
+
}
|
|
293
|
+
.ya-href-url-input {
|
|
294
|
+
width: 100%;
|
|
295
|
+
padding: 10px 12px;
|
|
296
|
+
background: rgba(255, 255, 255, 0.05);
|
|
297
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
298
|
+
border-radius: 8px;
|
|
299
|
+
color: #ffffff;
|
|
300
|
+
font-size: 13px;
|
|
301
|
+
outline: none;
|
|
302
|
+
transition: border-color 0.15s ease;
|
|
303
|
+
}
|
|
304
|
+
.ya-href-url-input::placeholder {
|
|
305
|
+
color: rgba(255, 255, 255, 0.4);
|
|
306
|
+
}
|
|
307
|
+
.ya-href-url-input:focus {
|
|
308
|
+
border-color: var(--color-primary, #D4A574);
|
|
309
|
+
}
|
|
310
|
+
.ya-href-popover-actions {
|
|
311
|
+
display: flex;
|
|
312
|
+
justify-content: flex-end;
|
|
313
|
+
gap: 8px;
|
|
314
|
+
padding: 12px 16px;
|
|
315
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
316
|
+
}
|
|
317
|
+
.ya-link-edit-popover {
|
|
318
|
+
position: absolute;
|
|
319
|
+
top: 100%;
|
|
320
|
+
left: 50%;
|
|
321
|
+
margin-top: 8px;
|
|
322
|
+
z-index: 10;
|
|
323
|
+
background: #2a2a2a;
|
|
324
|
+
border-radius: 6px;
|
|
325
|
+
padding: 4px;
|
|
326
|
+
display: flex;
|
|
327
|
+
gap: 4px;
|
|
328
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
329
|
+
transform: translateX(-50%);
|
|
330
|
+
animation: ya-edit-popover-fade-in 0.1s ease;
|
|
331
|
+
font-family:
|
|
332
|
+
system-ui,
|
|
333
|
+
-apple-system,
|
|
334
|
+
BlinkMacSystemFont,
|
|
335
|
+
"Segoe UI",
|
|
336
|
+
sans-serif;
|
|
337
|
+
white-space: nowrap;
|
|
338
|
+
}
|
|
339
|
+
@keyframes ya-edit-popover-fade-in {
|
|
340
|
+
from {
|
|
341
|
+
opacity: 0;
|
|
342
|
+
transform: translateX(-50%) translateY(-4px);
|
|
343
|
+
}
|
|
344
|
+
to {
|
|
345
|
+
opacity: 1;
|
|
346
|
+
transform: translateX(-50%) translateY(0);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
.ya-link-edit-popover::before {
|
|
350
|
+
content: "";
|
|
351
|
+
position: absolute;
|
|
352
|
+
top: -5px;
|
|
353
|
+
left: 50%;
|
|
354
|
+
transform: translateX(-50%);
|
|
355
|
+
border-left: 6px solid transparent;
|
|
356
|
+
border-right: 6px solid transparent;
|
|
357
|
+
border-bottom: 6px solid #2a2a2a;
|
|
358
|
+
}
|
|
359
|
+
.ya-link-edit-popover button {
|
|
360
|
+
background: #3a3a3a;
|
|
361
|
+
border: none;
|
|
362
|
+
color: #fff;
|
|
363
|
+
padding: 6px 12px;
|
|
364
|
+
border-radius: 4px;
|
|
365
|
+
cursor: pointer;
|
|
366
|
+
font-size: 13px;
|
|
367
|
+
font-weight: 500;
|
|
368
|
+
transition: background 0.15s ease;
|
|
369
|
+
}
|
|
370
|
+
.ya-link-edit-popover button:hover {
|
|
371
|
+
background: #4a4a4a;
|
|
372
|
+
}
|