Initial commit: WordPress wp-content (themes, plugins, languages)
- Theme: momentry (custom theme with REST API routes) - Plugins: code-snippets (contains all API proxies) - Languages: zh_TW translations - Excludes: cache, backups, uploads, logs
This commit is contained in:
27
plugins/code-snippets/js/components/common/Badge.tsx
Normal file
27
plugins/code-snippets/js/components/common/Badge.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
import type { ReactNode } from 'react'
|
||||
import type { SnippetType } from '../../types/Snippet'
|
||||
|
||||
export type BadgeName = SnippetType | 'core' | 'pro' | 'ai' | 'cloud' | 'bundles' | 'cloud_search' | 'beta'
|
||||
|
||||
const badgeIcons: Partial<Record<BadgeName, string>> = {
|
||||
cond: 'randomize',
|
||||
cloud: 'cloud',
|
||||
bundles: 'screenoptions',
|
||||
cloud_search: 'search'
|
||||
}
|
||||
|
||||
export interface BadgeProps {
|
||||
name: BadgeName
|
||||
small?: boolean
|
||||
inverted?: boolean
|
||||
children?: ReactNode
|
||||
}
|
||||
|
||||
export const Badge: React.FC<BadgeProps> = ({ name, small, inverted, children }) =>
|
||||
<span className={classnames('badge', `${name}-badge`, { 'small-badge': small, 'inverted-badge': inverted })}>
|
||||
{badgeIcons[name]
|
||||
? <span className={`dashicons dashicons-${badgeIcons[name]}`} />
|
||||
: children ?? name}
|
||||
</span>
|
||||
49
plugins/code-snippets/js/components/common/Button.tsx
Normal file
49
plugins/code-snippets/js/components/common/Button.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
import type { ButtonHTMLAttributes } from 'react'
|
||||
|
||||
export interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'id' | 'name'> {
|
||||
id?: string
|
||||
name?: string
|
||||
primary?: boolean
|
||||
secondary?: boolean
|
||||
small?: boolean
|
||||
large?: boolean
|
||||
link?: boolean
|
||||
}
|
||||
|
||||
export const Button: React.FC<ButtonProps> = ({
|
||||
id,
|
||||
children,
|
||||
className,
|
||||
name,
|
||||
primary = false,
|
||||
secondary = false,
|
||||
small = false,
|
||||
large = false,
|
||||
link = false,
|
||||
type = 'button',
|
||||
onClick,
|
||||
...props
|
||||
}) =>
|
||||
<button
|
||||
id={id ?? name}
|
||||
name={name}
|
||||
type={type}
|
||||
{...props}
|
||||
onClick={event => {
|
||||
if (onClick) {
|
||||
event.preventDefault()
|
||||
onClick(event)
|
||||
}
|
||||
}}
|
||||
className={classnames('button', className, {
|
||||
'button-primary': primary,
|
||||
'button-secondary': secondary,
|
||||
'button-large': large,
|
||||
'button-small': small,
|
||||
'button-link': link
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
49
plugins/code-snippets/js/components/common/ConfirmDialog.tsx
Normal file
49
plugins/code-snippets/js/components/common/ConfirmDialog.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React from 'react'
|
||||
import { __ } from '@wordpress/i18n'
|
||||
import { Button, Flex, Modal } from '@wordpress/components'
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
export interface ConfirmDialogProps {
|
||||
open?: boolean
|
||||
title: string
|
||||
onConfirm?: VoidFunction
|
||||
onCancel: VoidFunction
|
||||
confirmLabel?: string
|
||||
cancelLabel?: string
|
||||
children?: ReactNode,
|
||||
confirmButtonClassName?: string
|
||||
}
|
||||
|
||||
export const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
|
||||
open,
|
||||
title,
|
||||
onConfirm,
|
||||
onCancel,
|
||||
children,
|
||||
confirmLabel = __('OK', 'code-snippets'),
|
||||
cancelLabel = __('Cancel', 'code-snippets'),
|
||||
confirmButtonClassName
|
||||
}) =>
|
||||
open
|
||||
? <Modal
|
||||
title={title}
|
||||
onRequestClose={onCancel}
|
||||
closeButtonLabel={cancelLabel}
|
||||
isDismissible={true}
|
||||
onKeyDown={event => {
|
||||
if ('Enter' === event.key) {
|
||||
onConfirm?.()
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<Flex direction="row" justify="flex-end">
|
||||
<Button variant="tertiary" onClick={onCancel}>
|
||||
{cancelLabel}
|
||||
</Button>
|
||||
<Button variant="primary" onClick={onConfirm} className={confirmButtonClassName}>
|
||||
{confirmLabel}
|
||||
</Button>
|
||||
</Flex>
|
||||
</Modal>
|
||||
: null
|
||||
@@ -0,0 +1,71 @@
|
||||
import { Spinner } from '@wordpress/components'
|
||||
import { __ } from '@wordpress/i18n'
|
||||
import React, { useState } from 'react'
|
||||
import { Button } from './Button'
|
||||
import { CopyIcon } from './icons/CopyIcon'
|
||||
import type { ButtonProps } from './Button'
|
||||
|
||||
const TIMEOUT = 1500
|
||||
|
||||
enum Status {
|
||||
INITIAL,
|
||||
PROGRESSING,
|
||||
SUCCESS,
|
||||
ERROR
|
||||
}
|
||||
|
||||
interface StatusIconProps {
|
||||
status: Status
|
||||
}
|
||||
|
||||
const StatusIcon: React.FC<StatusIconProps> = ({ status }) => {
|
||||
switch (status) {
|
||||
case Status.INITIAL:
|
||||
return <CopyIcon />
|
||||
case Status.PROGRESSING:
|
||||
return <span className="spinner-wrapper"><Spinner /></span>
|
||||
case Status.SUCCESS:
|
||||
return <span className="dashicons dashicons-yes"></span>
|
||||
case Status.ERROR:
|
||||
return <span className="dashicons dashicons-warning"></span>
|
||||
}
|
||||
}
|
||||
|
||||
export interface CopyToClipboardButtonProps extends ButtonProps {
|
||||
text: string
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
export const CopyToClipboardButton: React.FC<CopyToClipboardButtonProps> = ({
|
||||
text,
|
||||
timeout = TIMEOUT,
|
||||
...props
|
||||
}) => {
|
||||
const [status, setStatus] = useState(Status.INITIAL)
|
||||
const clipboard = window.navigator.clipboard as Clipboard | undefined
|
||||
|
||||
const handleClick = () => {
|
||||
setStatus(Status.PROGRESSING)
|
||||
|
||||
clipboard?.writeText(text)
|
||||
.then(() => {
|
||||
setStatus(Status.SUCCESS)
|
||||
setTimeout(() => setStatus(Status.INITIAL), timeout)
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
console.error('Failed to copy text to clipboard.', error)
|
||||
setStatus(Status.ERROR)
|
||||
})
|
||||
}
|
||||
|
||||
return clipboard && window.isSecureContext
|
||||
? <Button
|
||||
className="code-snippets-copy-text"
|
||||
onClick={handleClick}
|
||||
{...props}
|
||||
>
|
||||
<StatusIcon status={status} />
|
||||
{__('Copy', 'code-snippets')}
|
||||
</Button>
|
||||
: null
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { __ } from '@wordpress/i18n'
|
||||
import classnames from 'classnames'
|
||||
import React from 'react'
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
export interface DismissibleNoticeProps {
|
||||
className?: classnames.Argument
|
||||
onDismiss: VoidFunction
|
||||
children?: ReactNode
|
||||
}
|
||||
|
||||
export const DismissibleNotice: React.FC<DismissibleNoticeProps> = ({ className, onDismiss, children }) =>
|
||||
<div id="message" className={classnames('notice fade is-dismissible', className)}>
|
||||
<>{children}</>
|
||||
|
||||
<button type="button" className="notice-dismiss" onClick={event => {
|
||||
event.preventDefault()
|
||||
onDismiss()
|
||||
}}>
|
||||
<span className="screen-reader-text">{__('Dismiss notice.', 'code-snippets')}</span>
|
||||
</button>
|
||||
</div>
|
||||
46
plugins/code-snippets/js/components/common/SubmitButton.tsx
Normal file
46
plugins/code-snippets/js/components/common/SubmitButton.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
import { __ } from '@wordpress/i18n'
|
||||
import type { InputHTMLAttributes } from 'react'
|
||||
|
||||
export interface SubmitButtonProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'id' | 'name' | 'value'> {
|
||||
id?: string
|
||||
name?: string
|
||||
primary?: boolean
|
||||
small?: boolean
|
||||
large?: boolean
|
||||
wrap?: boolean
|
||||
text?: string
|
||||
}
|
||||
|
||||
export const SubmitButton: React.FC<SubmitButtonProps> = ({
|
||||
id,
|
||||
text,
|
||||
name = 'submit',
|
||||
primary,
|
||||
small,
|
||||
large,
|
||||
wrap,
|
||||
className,
|
||||
...inputProps
|
||||
}) => {
|
||||
const button =
|
||||
<input
|
||||
id={id ?? name}
|
||||
type="submit"
|
||||
name={name}
|
||||
value={text ?? __('Save Changes', 'code-snippets')}
|
||||
className={classnames(
|
||||
'button',
|
||||
{
|
||||
'button-primary': primary,
|
||||
'button-small': small,
|
||||
'button-large': large
|
||||
},
|
||||
className
|
||||
)}
|
||||
{...inputProps}
|
||||
/>
|
||||
|
||||
return wrap ? <p className="submit">{button}</p> : button
|
||||
}
|
||||
25
plugins/code-snippets/js/components/common/Tooltip.tsx
Normal file
25
plugins/code-snippets/js/components/common/Tooltip.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
export interface TooltipProps {
|
||||
block?: boolean
|
||||
inline?: boolean
|
||||
start?: boolean
|
||||
end?: boolean
|
||||
icon?: ReactNode
|
||||
children: ReactNode
|
||||
className?: classnames.Argument
|
||||
}
|
||||
|
||||
export const Tooltip: React.FC<TooltipProps> = ({ block, inline, start, end, icon, className, children }) =>
|
||||
<div className={classnames(
|
||||
'tooltip',
|
||||
{ 'tooltip-block': block, 'tooltip-inline': inline, 'tooltip-start': start, 'tooltip-end': end },
|
||||
className
|
||||
)}>
|
||||
{icon ?? <span className="dashicons dashicons-editor-help"></span>}
|
||||
<div className="tooltip-content">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
37
plugins/code-snippets/js/components/common/UpsellBanner.tsx
Normal file
37
plugins/code-snippets/js/components/common/UpsellBanner.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { ExternalLink } from '@wordpress/components'
|
||||
import { createInterpolateElement } from '@wordpress/element'
|
||||
import { __ } from '@wordpress/i18n'
|
||||
import React, { useState } from 'react'
|
||||
import { isLicensed } from '../../utils/screen'
|
||||
import { Button } from './Button'
|
||||
|
||||
export const UpsellBanner = () => {
|
||||
const [isDismissed, setIsDismissed] = useState(false)
|
||||
|
||||
return isDismissed || isLicensed() || window.CODE_SNIPPETS_EDIT?.hideUpsell
|
||||
? null
|
||||
: <div className="code-snippets-upsell-banner">
|
||||
<img
|
||||
src={`${window.CODE_SNIPPETS?.urls.plugin}/assets/icon.svg`}
|
||||
alt={__('Code Snippets logo', 'code-snippets')}
|
||||
height="34"
|
||||
/>
|
||||
<p>
|
||||
{createInterpolateElement(
|
||||
__('Unlock <strong>cloud sync, snippet conditions, AI features</strong> and much more with Code Snippets Pro.', 'code-snippets'),
|
||||
{ strong: <strong /> }
|
||||
)}
|
||||
</p>
|
||||
|
||||
<ExternalLink
|
||||
className="button button-primary button-large"
|
||||
href="https://codesnippets.pro/pricing/"
|
||||
>
|
||||
{__('Get Started', 'code-snippets')}
|
||||
</ExternalLink>
|
||||
|
||||
<Button small link onClick={() => setIsDismissed(true)}>
|
||||
<span className="dashicons dashicons-no-alt"></span>
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
62
plugins/code-snippets/js/components/common/UpsellDialog.tsx
Normal file
62
plugins/code-snippets/js/components/common/UpsellDialog.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { createInterpolateElement } from '@wordpress/element'
|
||||
import React from 'react'
|
||||
import { __ } from '@wordpress/i18n'
|
||||
import { Modal } from '@wordpress/components'
|
||||
import type { Dispatch, SetStateAction } from 'react'
|
||||
|
||||
export interface UpsellDialogProps {
|
||||
isOpen: boolean
|
||||
setIsOpen: Dispatch<SetStateAction<boolean>>
|
||||
}
|
||||
|
||||
export const UpsellDialog: React.FC<UpsellDialogProps> = ({ isOpen, setIsOpen }) =>
|
||||
isOpen
|
||||
? <Modal
|
||||
title=""
|
||||
className="code-snippets-upsell-dialog"
|
||||
onRequestClose={() => {
|
||||
setIsOpen(false)
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={`${window.CODE_SNIPPETS?.urls.plugin}/assets/icon.svg`}
|
||||
alt={__('Code Snippets logo', 'code-snippets')}
|
||||
/>
|
||||
|
||||
<h1>
|
||||
{createInterpolateElement(
|
||||
__('Unlock all cloud sync features and many more, with <span>Code Snippets Pro</span>', 'code-snippets'),
|
||||
{ span: <span /> }
|
||||
)}
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
{createInterpolateElement(
|
||||
__('With Code Snippets Pro you can connect your WordPress sites to the code snippets cloud platform and be able to <strong>backup, synchronise, collaborate, and deploy</strong> your snippets from one central location.', 'code-snippets'),
|
||||
{ strong: <strong /> }
|
||||
)}
|
||||
</p>
|
||||
|
||||
<a
|
||||
href="https://codesnippets.pro/pricing/"
|
||||
className="button button-primary button-large"
|
||||
rel="noreferrer" target="_blank"
|
||||
>
|
||||
{__('Explore Code Snippets Pro', 'code-snippets')}
|
||||
</a>
|
||||
|
||||
<h2>{__("Here's what else you get with Pro:", 'code-snippets')}</h2>
|
||||
<ul>
|
||||
<li>{__('Create, explain and verify snippets with AI', 'code-snippets')}</li>
|
||||
<li>{__('Control when snippets run with Conditions', 'code-snippets')}</li>
|
||||
<li>{__('CSS stylesheet snippets', 'code-snippets')}</li>
|
||||
<li>{__('Minified JavaScript snippets', 'code-snippets')}</li>
|
||||
<li>{__('Editor blocks and Elementor widgets', 'code-snippets')}</li>
|
||||
<li>{__('Cloud sync and backup', 'code-snippets')}</li>
|
||||
<li>{__('Cloud share and deploy', 'code-snippets')}</li>
|
||||
<li>{__('Cloud bundles and teams', 'code-snippets')}</li>
|
||||
<li>{__('WP-CLI commands', 'code-snippets')}</li>
|
||||
<li>{__('And much more!', 'code-snippets')}</li>
|
||||
</ul>
|
||||
</Modal>
|
||||
: null
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from 'react'
|
||||
|
||||
export const CopyIcon = () =>
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12 6V4.5C12 4.10218 11.842 3.72064 11.5607 3.43934C11.2794 3.15804 10.8978 3 10.5 3H4.5C4.10218 3 3.72064 3.15804 3.43934 3.43934C3.15804 3.72064 3 4.10218 3 4.5V10.5C3 10.8978 3.15804 11.2794 3.43934 11.5607C3.72064 11.842 4.10218 12 4.5 12H6M6 7.5C6 7.10218 6.15804 6.72065 6.43934 6.43934C6.72065 6.15804 7.10218 6 7.5 6H13.5C13.8978 6 14.2794 6.15804 14.5607 6.43934C14.842 6.72065 15 7.10218 15 7.5V13.5C15 13.8978 14.842 14.2794 14.5607 14.5607C14.2794 14.842 13.8978 15 13.5 15H7.5C7.10218 15 6.72065 14.842 6.43934 14.5607C6.15804 14.2794 6 13.8978 6 13.5V7.5Z"
|
||||
stroke="#F0F0F0"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
@@ -0,0 +1,20 @@
|
||||
import React from 'react'
|
||||
|
||||
export const ExpandIcon = () =>
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 3H15V6" />
|
||||
<path d="M10.5 7.5L15 3L10.5 7.5Z" />
|
||||
<path d="M6 15H3V12" />
|
||||
<path d="M3 15L7.5 10.5L3 15Z" />
|
||||
<path d="M12 15H15V12" />
|
||||
<path d="M10.5 10.5L15 15L10.5 10.5Z" />
|
||||
<path d="M6 3H3V6" />
|
||||
<path d="M3 3L7.5 7.5L3 3Z" />
|
||||
<path
|
||||
d="M12 3H15M15 3V6M15 3L10.5 7.5M6 15H3M3 15V12M3 15L7.5 10.5M12 15H15M15 15V12M15 15L10.5 10.5M6 3H3M3 3V6M3 3L7.5 7.5"
|
||||
stroke="currentcolor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
@@ -0,0 +1,20 @@
|
||||
import React from 'react'
|
||||
|
||||
export const MinimiseIcon = () =>
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.75 6.75H6.75V3.75" />
|
||||
<path d="M2.25 2.25L6.75 6.75L2.25 2.25Z" />
|
||||
<path d="M3.75 11.25H6.75V14.25" />
|
||||
<path d="M2.25 15.75L6.75 11.25L2.25 15.75Z" />
|
||||
<path d="M14.25 6.75H11.25V3.75" />
|
||||
<path d="M11.25 6.75L15.75 2.25L11.25 6.75Z" />
|
||||
<path d="M14.25 11.25H11.25V14.25" />
|
||||
<path d="M11.25 11.25L15.75 15.75L11.25 11.25Z" />
|
||||
<path
|
||||
d="M3.75 6.75H6.75M6.75 6.75V3.75M6.75 6.75L2.25 2.25M3.75 11.25H6.75M6.75 11.25V14.25M6.75 11.25L2.25 15.75M14.25 6.75H11.25M11.25 6.75V3.75M11.25 6.75L15.75 2.25M14.25 11.25H11.25M11.25 11.25V14.25M11.25 11.25L15.75 15.75"
|
||||
stroke="currentcolor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
Reference in New Issue
Block a user