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:
OpenCode
2026-05-29 19:07:56 +08:00
commit 09ef1f000f
6521 changed files with 867163 additions and 0 deletions

View File

@@ -0,0 +1,94 @@
import React, { useEffect, useRef } from 'react'
import { __ } from '@wordpress/i18n'
import { useSubmitSnippet } from '../../../hooks/useSubmitSnippet'
import { handleUnknownError } from '../../../utils/errors'
import { isMacOS } from '../../../utils/screen'
import { useSnippetForm } from '../../../hooks/useSnippetForm'
import { Button } from '../../common/Button'
import { ExpandIcon } from '../../common/icons/ExpandIcon'
import { MinimiseIcon } from '../../common/icons/MinimiseIcon'
import { CodeEditorShortcuts } from './CodeEditorShortcuts'
import type { Dispatch, RefObject, SetStateAction } from 'react'
interface EditorTextareaProps {
textareaRef: RefObject<HTMLTextAreaElement>
}
const EditorTextarea: React.FC<EditorTextareaProps> = ({ textareaRef }) => {
const { snippet, setSnippet } = useSnippetForm()
return (
<div className="snippet-editor">
<textarea
ref={textareaRef}
id="snippet-code"
name="snippet_code"
value={snippet.code}
rows={200}
spellCheck={false}
onChange={event => {
setSnippet(previous => ({ ...previous, code: event.target.value }))
}}
/>
<CodeEditorShortcuts editorTheme={window.CODE_SNIPPETS_EDIT?.editorTheme ?? 'default'} />
</div>
)
}
export interface CodeEditorProps {
isExpanded: boolean
setIsExpanded: Dispatch<SetStateAction<boolean>>
}
export const CodeEditor: React.FC<CodeEditorProps> = ({ isExpanded, setIsExpanded }) => {
const { snippet, setSnippet, codeEditorInstance, setCodeEditorInstance } = useSnippetForm()
const { submitSnippet } = useSubmitSnippet()
const textareaRef = useRef<HTMLTextAreaElement>(null)
useEffect(() => {
setCodeEditorInstance(editorInstance => {
if (textareaRef.current && !editorInstance) {
editorInstance = window.wp.codeEditor.initialize(textareaRef.current)
editorInstance.codemirror.on('changes', instance => {
setSnippet(previous => ({ ...previous, code: instance.getValue() }))
})
}
return editorInstance
})
}, [setCodeEditorInstance, textareaRef, setSnippet])
useEffect(() => {
if (codeEditorInstance) {
const extraKeys = codeEditorInstance.codemirror.getOption('extraKeys') ?? {}
const controlKey = isMacOS() ? 'Cmd' : 'Ctrl'
const onSave = () => {
submitSnippet()
.then(() => undefined)
.catch(handleUnknownError)
}
codeEditorInstance.codemirror.setOption('extraKeys', {
...'object' === typeof extraKeys ? extraKeys : undefined,
[`${controlKey}-S`]: onSave,
[`${controlKey}-Enter`]: onSave
})
}
}, [submitSnippet, codeEditorInstance, snippet])
return (
<div className="snippet-code-container">
<div className="above-snippet-code">
<h2><label htmlFor="snippet-code">{__('Snippet Content', 'code-snippets')}</label></h2>
<Button small className="expand-editor-button" onClick={() => setIsExpanded(current => !current)}>
{isExpanded ? <MinimiseIcon /> : <ExpandIcon />}
{isExpanded ? __('Minimize', 'code-snippets') : __('Expand', 'code-snippets')}
</Button>
</div>
<EditorTextarea textareaRef={textareaRef} />
</div>
)
}

View File

@@ -0,0 +1,123 @@
import { __, _x } from '@wordpress/i18n'
import classnames from 'classnames'
import React from 'react'
import { KEYBOARD_KEYS } from '../../../types/KeyboardShortcut'
import { isMacOS } from '../../../utils/screen'
import type { KeyboardKey, KeyboardShortcut } from '../../../types/KeyboardShortcut'
const shortcuts: Record<string, KeyboardShortcut> = {
saveChanges: {
label: __('Save changes', 'code-snippets'),
mod: 'Cmd',
key: 'S'
},
selectAll: {
label: __('Select all', 'code-snippets'),
mod: 'Cmd',
key: 'A'
},
beginSearch: {
label: __('Begin searching', 'code-snippets'),
mod: 'Cmd',
key: 'F'
},
findNext: {
label: __('Find next', 'code-snippets'),
mod: 'Cmd',
key: 'G'
},
findPrevious: {
label: __('Find previous', 'code-snippets'),
mod: ['Shift', 'Cmd'],
key: 'G'
},
replace: {
label: __('Replace', 'code-snippets'),
mod: ['Shift', 'Cmd'],
key: 'F'
},
replaceAll: {
label: __('Replace all', 'code-snippets'),
mod: ['Shift', 'Cmd', 'Option'],
key: 'R'
},
search: {
label: __('Persistent search', 'code-snippets'),
mod: 'Alt',
key: 'F'
},
toggleComment: {
label: __('Toggle comment', 'code-snippets'),
mod: 'Cmd',
key: '/'
},
swapLineUp: {
label: __('Swap line up', 'code-snippets'),
mod: 'Option',
key: 'Up'
},
swapLineDown: {
label: __('Swap line down', 'code-snippets'),
mod: 'Option',
key: 'Down'
},
autoIndent: {
label: __('Auto-indent current line or selection', 'code-snippets'),
mod: 'Shift',
key: 'Tab'
}
}
const SEP = _x('-', 'keyboard shortcut separator', 'code-snippets')
const ModifierKey: React.FC<{ modifier: KeyboardKey }> = ({ modifier }) => {
switch (modifier) {
case 'Ctrl':
case 'Cmd':
return (
<>
<kbd className="pc-key">{KEYBOARD_KEYS.Ctrl}</kbd>
<kbd className="mac-key">{KEYBOARD_KEYS.Cmd}</kbd>
{SEP}
</>
)
case 'Option':
return (
<span className="mac-key">
<kbd className="mac-key">{KEYBOARD_KEYS.Option}</kbd>{SEP}
</span>
)
default:
return <><kbd>{KEYBOARD_KEYS[modifier]}</kbd>{SEP}</>
}
}
export interface CodeEditorShortcutsProps {
editorTheme: string
}
export const CodeEditorShortcuts: React.FC<CodeEditorShortcutsProps> = ({ editorTheme }) =>
<div className="snippet-editor-help tooltip tooltip-inline tooltip-start">
<span className={`dashicons dashicons-editor-help cm-s-${editorTheme}`}></span>
<div className={classnames('tooltip-content', { 'platform-mac': isMacOS() })}>
<table>
<tbody>
{Object.entries(shortcuts).map(([name, { label, mod, key }]) =>
<tr key={name}>
<td>{label}</td>
<td>
{(Array.isArray(mod) ? mod : [mod]).map(modifier =>
<span key={modifier}>
<ModifierKey modifier={modifier} />
</span>
)}
<kbd>{KEYBOARD_KEYS[key]}</kbd>
</td>
</tr>)}
</tbody>
</table>
</div>
</div>

View File

@@ -0,0 +1,88 @@
import React, { useCallback, useEffect } from 'react'
import { __ } from '@wordpress/i18n'
import domReady from '@wordpress/dom-ready'
import { useSnippetForm } from '../../../hooks/useSnippetForm'
export const EDITOR_ID = 'snippet_description'
const TOOLBAR_BUTTONS = [
[
'bold',
'italic',
'underline',
'strikethrough',
'blockquote',
'bullist',
'numlist',
'alignleft',
'aligncenter',
'alignright',
'link',
'wp_adv',
'code_snippets'
],
[
'formatselect',
'forecolor',
'pastetext',
'removeformat',
'charmap',
'outdent',
'indent',
'undo',
'redo',
'spellchecker'
]
]
const initializeEditor = (onChange: (content: string) => void) => {
window.wp.editor?.initialize(EDITOR_ID, {
mediaButtons: window.CODE_SNIPPETS_EDIT?.descEditorOptions.mediaButtons,
quicktags: true,
tinymce: {
toolbar: TOOLBAR_BUTTONS.map(line => line.join(' ')),
setup: editor => {
editor.on('change', () => onChange(editor.getContent()))
}
}
})
}
const DescriptionEditorTextarea: React.FC = () => {
const { snippet, setSnippet, isReadOnly } = useSnippetForm()
const handleChange = useCallback(
(desc: string) => setSnippet(previous => ({ ...previous, desc })),
[setSnippet]
)
useEffect(() => {
domReady(() => initializeEditor(handleChange))
}, [handleChange])
return (
<textarea
id={EDITOR_ID}
className="wp-editor-area"
onChange={event => handleChange(event.target.value)}
autoComplete="off"
disabled={isReadOnly}
rows={window.CODE_SNIPPETS_EDIT?.descEditorOptions.rows}
cols={40}
value={snippet.desc}
/>
)
}
export const DescriptionEditor: React.FC = () =>
window.CODE_SNIPPETS_EDIT?.enableDescription
? <div className="snippet-description-container">
<h2>
<label htmlFor={EDITOR_ID}>
{__('Description', 'code-snippets')}
</label>
</h2>
<DescriptionEditorTextarea />
</div>
: null

View File

@@ -0,0 +1,28 @@
import React from 'react'
import { __ } from '@wordpress/i18n'
import { useSnippetForm } from '../../../hooks/useSnippetForm'
export const NameInput: React.FC = () => {
const { snippet, setSnippet, isReadOnly } = useSnippetForm()
return (
<div id="titlediv">
<div id="titlewrap">
<label htmlFor="title" className="screen-reader-text">
{__('Name', 'code-snippets')}
</label>
<input
id="title"
type="text"
name="snippet_name"
autoComplete="off"
value={snippet.name}
disabled={isReadOnly}
placeholder={__('Enter snippet title', 'code-snippets')}
onChange={event =>
setSnippet(previous => ({ ...previous, name: event.target.value }))}
/>
</div>
</div>
)
}

View File

@@ -0,0 +1,72 @@
import { __ } from '@wordpress/i18n'
import React from 'react'
import Select from 'react-select'
import { useSnippetForm } from '../../../hooks/useSnippetForm'
import { SNIPPET_TYPE_SCOPES } from '../../../types/Snippet'
import { getSnippetType, isCondition } from '../../../utils/snippets/snippets'
import type { SnippetCodeScope } from '../../../types/Snippet'
import type { SelectOption } from '../../../types/SelectOption'
const SCOPE_ICONS: Record<SnippetCodeScope, string> = {
'global': 'admin-site',
'admin': 'admin-tools',
'front-end': 'admin-appearance',
'single-use': 'clock',
'content': 'shortcode',
'head-content': 'editor-code',
'footer-content': 'editor-code',
'admin-css': 'dashboard',
'site-css': 'admin-customizer',
'site-head-js': 'media-code',
'site-footer-js': 'media-code'
}
const SCOPE_DESCRIPTIONS: Record<SnippetCodeScope, string> = {
'global': __('Run everywhere', 'code-snippets'),
'admin': __('Only run in administration area', 'code-snippets'),
'front-end': __('Only run on site front-end', 'code-snippets'),
'single-use': __('Only run once', 'code-snippets'),
'content': __('Where inserted in editor', 'code-snippets'),
'head-content': __('In site <head> section', 'code-snippets'),
'footer-content': __('In site footer (end of <body>)', 'code-snippets'),
'site-css': __('Site front-end', 'code-snippets'),
'admin-css': __('Administration area', 'code-snippets'),
'site-footer-js': __('In site footer (end of <body>)', 'code-snippets'),
'site-head-js': __('In site <head> section', 'code-snippets')
}
export const SnippetLocationInput: React.FC = () => {
const { snippet, setSnippet, isReadOnly } = useSnippetForm()
const options: SelectOption<SnippetCodeScope>[] = SNIPPET_TYPE_SCOPES[getSnippetType(snippet)]
.filter(scope => 'condition' !== scope)
.map(scope => ({
key: scope,
value: scope,
label: SCOPE_DESCRIPTIONS[scope]
}))
return isCondition(snippet)
? null
: <div className="block-form-field">
<h4><label htmlFor="snippet-location">{__('Location', 'code-snippets')}</label></h4>
<Select
inputId="snippet-location"
className="code-snippets-select code-snippets-select-location"
options={options}
isDisabled={isReadOnly}
styles={{
menu: provided => ({ ...provided, zIndex: 9999 }),
input: provided => ({ ...provided, ':focus': { boxShadow: 'none' } })
}}
value={options.find(option => option.value === snippet.scope)}
formatOptionLabel={({ label, value }) =>
<>
<span className={`dashicons dashicons-${SCOPE_ICONS[value]}`}></span>{` ${label}`}
</>
}
onChange={option =>
option?.value && setSnippet(previous => ({ ...previous, scope: option.value }))}
/>
</div>
}

View File

@@ -0,0 +1,106 @@
import React, { useEffect } from 'react'
import classnames from 'classnames'
import { __, _x } from '@wordpress/i18n'
import Select from 'react-select'
import { useSnippetForm } from '../../../hooks/useSnippetForm'
import { SNIPPET_TYPE_SCOPES } from '../../../types/Snippet'
import { isLicensed } from '../../../utils/screen'
import { getSnippetType, isProType } from '../../../utils/snippets/snippets'
import { Badge } from '../../common/Badge'
import type { FormatOptionLabelContext } from 'react-select'
import type { Dispatch, SetStateAction } from 'react'
import type { SnippetCodeType, SnippetType } from '../../../types/Snippet'
import type { SelectOption } from '../../../types/SelectOption'
import type { EditorConfiguration } from 'codemirror'
export interface SnippetTypeInputProps {
setIsUpgradeDialogOpen: Dispatch<SetStateAction<boolean>>
}
const EDITOR_MODES: Record<SnippetCodeType, string> = {
css: 'text/css',
js: 'javascript',
php: 'text/x-php',
html: 'application/x-httpd-php'
}
const OPTIONS: SelectOption<SnippetType>[] = [
{ value: 'php', label: __('Functions', 'code-snippets') },
{ value: 'html', label: __('Content', 'code-snippets') },
{ value: 'css', label: __('Styles', 'code-snippets') },
{ value: 'js', label: __('Scripts', 'code-snippets') },
{ value: 'cond', label: __('Conditions', 'code-snippets') }
]
interface SnippetTypeOptionProps {
option: SelectOption<SnippetType>
context: FormatOptionLabelContext
}
const SnippetTypeOption: React.FC<SnippetTypeOptionProps> = ({ option: { value, label }, context }) =>
<div className={classnames('snippet-type-option', { 'inverted-badges': isProType(value) && !isLicensed() })}>
{'menu' === context
? <div>
{label}
{isProType(value) && !isLicensed()
? <Badge name="pro" small>{_x('Pro', 'Upgrade to Pro', 'code-snippets')}</Badge>
: null}
</div>
: null}
<Badge name={value} />
</div>
export const SnippetTypeInput: React.FC<SnippetTypeInputProps> = ({ setIsUpgradeDialogOpen }) => {
const { snippet, setSnippet, codeEditorInstance, isReadOnly } = useSnippetForm()
const snippetType = getSnippetType(snippet)
useEffect(() => {
if (codeEditorInstance) {
const codeEditor = codeEditorInstance.codemirror
codeEditor.setOption('lint' as keyof EditorConfiguration, 'php' === snippetType || 'css' === snippetType)
if ('cond' !== snippetType && EDITOR_MODES[snippetType]) {
codeEditor.setOption('mode', EDITOR_MODES[snippetType])
codeEditor.refresh()
}
}
}, [codeEditorInstance, snippetType])
return (
<div className="snippet-type-container">
<label htmlFor="snippet-type-select-input" className="screen-reader-text">
{__('Snippet Type', 'code-snippets')}
</label>
<Select
inputId="snippet-type-select-input"
className="code-snippets-select"
isDisabled={isReadOnly}
options={0 === snippet.id ? OPTIONS : OPTIONS.filter(option => 'cond' !== option.value)}
menuPlacement="bottom"
styles={{
menu: provided => ({
...provided,
zIndex: 9999,
width: 'max-content',
minWidth: '100%'
}),
input: provided => ({ ...provided, boxShadow: 'none' })
}}
value={OPTIONS.find(option => option.value === snippetType)}
formatOptionLabel={(data, meta) =>
<SnippetTypeOption option={data} context={meta.context} />}
onChange={option => {
if (option && isProType(option.value) && !isLicensed()) {
setIsUpgradeDialogOpen(true)
} else if (option) {
setSnippet(previous => ({
...previous,
scope: SNIPPET_TYPE_SCOPES[option.value][0]
}))
}
}}
/>
</div>
)
}

View File

@@ -0,0 +1,31 @@
import React from 'react'
import { __ } from '@wordpress/i18n'
import { FormTokenField } from '@wordpress/components'
import { useSnippetForm } from '../../../hooks/useSnippetForm'
const options = window.CODE_SNIPPETS_EDIT?.tagOptions
export const TagsEditor: React.FC = () => {
const { snippet, setSnippet, isReadOnly } = useSnippetForm()
return options?.enabled
? <div className="snippet-tags-container">
<h3><label htmlFor="components-form-token-input-0">{__('Snippet Tags', 'code-snippets')}</label></h3>
<FormTokenField
label=""
value={snippet.tags}
disabled={isReadOnly}
suggestions={options.availableTags}
tokenizeOnBlur
tokenizeOnSpace={!options.allowSpaces}
onChange={tokens => {
setSnippet(previous => ({
...previous,
tags: tokens.map(token => 'string' === typeof token ? token : token.value)
}))
}}
/>
</div>
: null
}