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,142 @@
import React, { useState } from 'react'
import { __ } from '@wordpress/i18n'
import {
ImporterSelector,
ImportOptions,
SimpleSnippetTable,
StatusDisplay
} from './components'
import { ImportCard } from '../shared'
import {
useImporterSelection,
useSnippetImport,
useImportSnippetSelection
} from './hooks'
export const ImportForm: React.FC = () => {
const [autoAddTags, setAutoAddTags] = useState<boolean>(false)
const importerSelection = useImporterSelection()
const snippetImport = useSnippetImport()
const snippetSelection = useImportSnippetSelection(snippetImport.snippets)
const handleImporterChange = async (newImporter: string) => {
importerSelection.handleImporterChange(newImporter)
snippetSelection.clearSelection()
snippetImport.resetAll()
if (newImporter) {
await snippetImport.loadSnippets(newImporter)
}
}
const handleImport = async () => {
const selectedIds = Array.from(snippetSelection.selectedSnippets)
const success = await snippetImport.importSnippets(
importerSelection.selectedImporter,
selectedIds,
autoAddTags,
importerSelection.tagValue
)
if (success) {
snippetSelection.clearSelection()
}
}
if (importerSelection.isLoading) {
return (
<div className="wrap">
<p>{__('Loading importers...', 'code-snippets')}</p>
</div>
)
}
if (importerSelection.error) {
return (
<div className="wrap">
<div className="notice notice-error">
<p>{__('Error loading importers:', 'code-snippets')} {importerSelection.error}</p>
</div>
</div>
)
}
return (
<div className="wrap">
<div className="import-form-container" style={{ maxWidth: '800px' }}>
<p>{__('If you are using another Snippets plugin, you can import all existing snippets to your Code Snippets library.', 'code-snippets')}</p>
<ImporterSelector
importers={importerSelection.importers}
selectedImporter={importerSelection.selectedImporter}
onImporterChange={handleImporterChange}
isLoading={snippetImport.isLoadingSnippets}
/>
{snippetImport.snippetsError && (
<StatusDisplay
type="error"
title={__('Error loading snippets', 'code-snippets')}
message={snippetImport.snippetsError}
/>
)}
{snippetImport.importError && (
<StatusDisplay
type="error"
title={__('Error importing snippets', 'code-snippets')}
message={snippetImport.importError}
/>
)}
{snippetImport.importSuccess.length > 0 && (
<StatusDisplay
type="success"
title={`${snippetImport.importSuccess.length} ${__('Snippets imported!', 'code-snippets')}`}
message={__('We successfully imported all snippets to your library. Go to ', 'code-snippets')}
showSnippetsLink
/>
)}
{importerSelection.selectedImporter &&
!snippetImport.isLoadingSnippets &&
!snippetImport.snippetsError &&
snippetImport.snippets.length === 0 &&
snippetImport.importSuccess.length === 0 && (
<ImportCard>
<div style={{ textAlign: 'center', padding: '40px 20px', color: '#666' }}>
<div style={{ fontSize: '48px', marginBottom: '16px' }}>📭</div>
<h3 style={{ margin: '0 0 8px 0', fontSize: '18px', color: '#333' }}>
{__('No snippets found', 'code-snippets')}
</h3>
<p style={{ margin: '0', fontSize: '14px' }}>
{__('No snippets were found for the selected plugin. Make sure the plugin is installed and has snippets configured.', 'code-snippets')}
</p>
</div>
</ImportCard>
)}
{snippetImport.snippets.length > 0 && (
<>
<ImportOptions
autoAddTags={autoAddTags}
tagValue={importerSelection.tagValue}
onAutoAddTagsChange={setAutoAddTags}
onTagValueChange={importerSelection.setTagValue}
/>
<SimpleSnippetTable
snippets={snippetImport.snippets}
selectedSnippets={snippetSelection.selectedSnippets}
onSnippetToggle={snippetSelection.handleSnippetToggle}
onSelectAll={snippetSelection.handleSelectAll}
onImport={handleImport}
isImporting={snippetImport.isImporting}
/>
</>
)}
</div>
</div>
)
}

View File

@@ -0,0 +1,52 @@
import React from 'react'
import { __ } from '@wordpress/i18n'
import { ImportCard } from '../../shared'
interface ImportOptionsProps {
autoAddTags: boolean
tagValue: string
onAutoAddTagsChange: (enabled: boolean) => void
onTagValueChange: (value: string) => void
}
export const ImportOptions: React.FC<ImportOptionsProps> = ({
autoAddTags,
tagValue,
onAutoAddTagsChange,
onTagValueChange
}) => {
return (
<ImportCard>
<h2 style={{ margin: '0 0 1em 0' }}>{__('Import options', 'code-snippets')}</h2>
<label style={{ display: 'flex', alignItems: 'flex-start', gap: '8px', cursor: 'pointer' }}>
<input
type="checkbox"
checked={autoAddTags}
onChange={(e) => onAutoAddTagsChange(e.target.checked)}
style={{ marginTop: '2px' }}
/>
<div style={{ flex: 1 }}>
<div>
<strong>{__('Automatically add Tag', 'code-snippets')}</strong>
<br />
<span style={{ color: '#666', fontSize: '0.9em' }}>
{__('For your convenience, we can add a tag on every imported snippet.', 'code-snippets')}
</span>
</div>
{autoAddTags && (
<div style={{ marginTop: '12px' }}>
<input
type="text"
value={tagValue}
onChange={(e) => onTagValueChange(e.target.value)}
placeholder={__('Add tag...', 'code-snippets')}
className="regular-text"
style={{ width: '100%', maxWidth: '300px' }}
/>
</div>
)}
</div>
</label>
</ImportCard>
)
}

View File

@@ -0,0 +1,50 @@
import React from 'react'
import { __ } from '@wordpress/i18n'
import type { Importer } from '../../../../hooks/useImportersAPI'
import { ImportCard } from '../../shared'
interface ImporterSelectorProps {
importers: Importer[]
selectedImporter: string
onImporterChange: (importerName: string) => void
isLoading: boolean
}
export const ImporterSelector: React.FC<ImporterSelectorProps> = ({
importers,
selectedImporter,
onImporterChange,
isLoading
}) => {
return (
<ImportCard variant="controls">
<label htmlFor="importer-select">
<h2 style={{ margin: '0 0 1em 0' }}>{__('Select Plugin', 'code-snippets')}</h2>
</label>
<select
id="importer-select"
value={selectedImporter}
onChange={(event) => onImporterChange(event.target.value)}
className="regular-text"
style={{ display: 'block', marginTop: '5px', width: '100%', maxWidth: '300px' }}
disabled={isLoading}
>
<option value="">{__('-- Select an importer --', 'code-snippets')}</option>
{importers.map(importer => (
<option
key={importer.name}
value={importer.name}
disabled={!importer.is_active}
>
{importer.title} {!importer.is_active ? __('(Inactive)', 'code-snippets') : ''}
</option>
))}
</select>
{isLoading && (
<p style={{ margin: '10px 0 0 0', color: '#666', fontSize: '14px' }}>
{__('Loading snippets...', 'code-snippets')}
</p>
)}
</ImportCard>
)
}

View File

@@ -0,0 +1,102 @@
import React from 'react'
import { __ } from '@wordpress/i18n'
import { Button } from '../../../common/Button'
import type { ImportableSnippet } from '../../../../hooks/useImportersAPI'
import { ImportCard } from '../../shared'
interface SimpleSnippetTableProps {
snippets: ImportableSnippet[]
selectedSnippets: Set<number>
onSnippetToggle: (snippetId: number) => void
onSelectAll: () => void
onImport: () => void
isImporting: boolean
}
export const SimpleSnippetTable: React.FC<SimpleSnippetTableProps> = ({
snippets,
selectedSnippets,
onSnippetToggle,
onSelectAll,
onImport,
isImporting
}) => {
const isAllSelected = selectedSnippets.size === snippets.length && snippets.length > 0
return (
<ImportCard className="snippets-table-container">
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}>
<div>
<h2 style={{ margin: '0' }}>{__('Available Snippets', 'code-snippets')} ({snippets.length})</h2>
<p style={{ margin: '0.5em 0 1em 0' }}>{__('We found the following snippets.', 'code-snippets')}</p>
</div>
<div>
<Button onClick={onSelectAll} style={{ marginRight: '10px' }}>
{isAllSelected
? __('Deselect All', 'code-snippets')
: __('Select All', 'code-snippets')
}
</Button>
<Button
primary
onClick={onImport}
disabled={selectedSnippets.size === 0 || isImporting}
>
{isImporting
? __('Importing...', 'code-snippets')
: __('Import Selected', 'code-snippets')} ({selectedSnippets.size})
</Button>
</div>
</div>
<table className="wp-list-table widefat fixed striped" style={{ borderRadius: '5px' }}>
<thead>
<tr>
<th scope="col" className="check-column" style={{ padding: '8px 0' }}>
<input
type="checkbox"
checked={isAllSelected}
onChange={onSelectAll}
/>
</th>
<th scope="col">{__('Snippet Name', 'code-snippets')}</th>
<th scope="col" style={{ textAlign: 'end', width: '50px' }}>{__('ID', 'code-snippets')}</th>
</tr>
</thead>
<tbody>
{snippets.map(snippet => (
<tr key={snippet.table_data.id}>
<th scope="row" className="check-column">
<input
type="checkbox"
checked={selectedSnippets.has(snippet.table_data.id)}
onChange={() => onSnippetToggle(snippet.table_data.id)}
/>
</th>
<td>{snippet.table_data.title}</td>
<td style={{ textAlign: 'end', width: '50px' }}>{snippet.table_data.id}</td>
</tr>
))}
</tbody>
</table>
<div style={{ textAlign: 'end', marginTop: '1em' }}>
<Button onClick={onSelectAll} style={{ marginRight: '10px' }}>
{isAllSelected
? __('Deselect All', 'code-snippets')
: __('Select All', 'code-snippets')
}
</Button>
<Button
primary
onClick={onImport}
disabled={selectedSnippets.size === 0 || isImporting}
>
{isImporting
? __('Importing...', 'code-snippets')
: __('Import Selected', 'code-snippets')} ({selectedSnippets.size})
</Button>
</div>
</ImportCard>
)
}

View File

@@ -0,0 +1,55 @@
import React from 'react'
import { __ } from '@wordpress/i18n'
import { ImportCard } from '../../shared'
interface StatusDisplayProps {
type: 'error' | 'success'
title: string
message: string
showSnippetsLink?: boolean
}
export const StatusDisplay: React.FC<StatusDisplayProps> = ({
type,
title,
message,
showSnippetsLink = false
}) => {
const isError = type === 'error'
return (
<ImportCard variant="controls" style={{ display: 'flex', alignItems: 'flex-start', gap: '12px', marginBottom: '20px' }}>
<div style={{
backgroundColor: isError ? '#d63638' : '#00a32a',
borderRadius: '50%',
width: '24px',
height: '24px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
marginTop: '2px'
}}>
<span style={{ color: 'white', fontSize: '14px', fontWeight: 'bold' }}>
{isError ? '✕' : '✓'}
</span>
</div>
<div>
<h3 style={{ margin: '0 0 8px 0', fontSize: '16px', fontWeight: '600' }}>
{title}
</h3>
<p style={{ margin: '0', color: '#666' }}>
{message}
{showSnippetsLink && (
<>
{' '}
<a href="admin.php?page=snippets" style={{ color: '#2271b1', textDecoration: 'none' }}>
{__('Code Snippets Library', 'code-snippets')}
</a>.
</>
)}
</p>
</div>
</ImportCard>
)
}

View File

@@ -0,0 +1,4 @@
export { ImporterSelector } from './ImporterSelector'
export { ImportOptions } from './ImportOptions'
export { SimpleSnippetTable } from './SimpleSnippetTable'
export { StatusDisplay } from './StatusDisplay'

View File

@@ -0,0 +1,3 @@
export { useImporterSelection } from './useImporterSelection'
export { useSnippetImport } from './useSnippetImport'
export { useImportSnippetSelection } from './useImportSnippetSelection'

View File

@@ -0,0 +1,45 @@
import { useState } from 'react'
import type { ImportableSnippet } from '../../../../hooks/useImportersAPI'
export const useImportSnippetSelection = (availableSnippets: ImportableSnippet[]) => {
const [selectedSnippets, setSelectedSnippets] = useState<Set<number>>(new Set())
const handleSnippetToggle = (snippetId: number) => {
const newSelected = new Set(selectedSnippets)
if (newSelected.has(snippetId)) {
newSelected.delete(snippetId)
} else {
newSelected.add(snippetId)
}
setSelectedSnippets(newSelected)
}
const handleSelectAll = () => {
if (selectedSnippets.size === availableSnippets.length) {
setSelectedSnippets(new Set())
} else {
setSelectedSnippets(new Set(availableSnippets.map(snippet => snippet.table_data.id)))
}
}
const clearSelection = () => {
setSelectedSnippets(new Set())
}
const getSelectedSnippets = () => {
return availableSnippets.filter(snippet =>
selectedSnippets.has(snippet.table_data.id)
)
}
const isAllSelected = selectedSnippets.size === availableSnippets.length && availableSnippets.length > 0
return {
selectedSnippets,
handleSnippetToggle,
handleSelectAll,
clearSelection,
getSelectedSnippets,
isAllSelected
}
}

View File

@@ -0,0 +1,42 @@
import { useState, useEffect } from 'react'
import { useImportersAPI, type Importer } from '../../../../hooks/useImportersAPI'
export const useImporterSelection = () => {
const [importers, setImporters] = useState<Importer[]>([])
const [selectedImporter, setSelectedImporter] = useState<string>('')
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [tagValue, setTagValue] = useState<string>('')
const importersAPI = useImportersAPI()
useEffect(() => {
const fetchImporters = async () => {
try {
const response = await importersAPI.fetchAll()
setImporters(response.data)
} catch (err) {
setError(err instanceof Error ? err.message : 'Unknown error')
} finally {
setIsLoading(false)
}
}
fetchImporters()
}, [importersAPI])
const handleImporterChange = (newImporter: string) => {
setSelectedImporter(newImporter)
setTagValue(`imported-${newImporter}`)
}
return {
importers,
selectedImporter,
isLoading,
error,
tagValue,
setTagValue,
handleImporterChange
}
}

View File

@@ -0,0 +1,107 @@
import { useState } from 'react'
import { __ } from '@wordpress/i18n'
import { useImportersAPI, type ImportableSnippet } from '../../../../hooks/useImportersAPI'
import { isNetworkAdmin } from '../../../../utils/screen'
export const useSnippetImport = () => {
const [snippets, setSnippets] = useState<ImportableSnippet[]>([])
const [isLoadingSnippets, setIsLoadingSnippets] = useState(false)
const [snippetsError, setSnippetsError] = useState<string | null>(null)
const [isImporting, setIsImporting] = useState(false)
const [importError, setImportError] = useState<string | null>(null)
const [importSuccess, setImportSuccess] = useState<number[]>([])
const importersAPI = useImportersAPI()
const loadSnippets = async (importerName: string): Promise<boolean> => {
if (!importerName) {
alert(__('Please select an importer.', 'code-snippets'))
return false
}
setIsLoadingSnippets(true)
setSnippetsError(null)
setSnippets([])
clearResults()
try {
const response = await importersAPI.fetchSnippets(importerName)
setSnippets(response.data)
return true
} catch (err) {
setSnippetsError(err instanceof Error ? err.message : 'Unknown error')
return false
} finally {
setIsLoadingSnippets(false)
}
}
const importSnippets = async (
importerName: string,
selectedSnippetIds: number[],
autoAddTags: boolean,
tagValue: string
): Promise<boolean> => {
if (selectedSnippetIds.length === 0) {
alert(__('Please select snippets to import.', 'code-snippets'))
return false
}
if (!importerName) {
alert(__('Please select an importer.', 'code-snippets'))
return false
}
setIsImporting(true)
setImportError(null)
setImportSuccess([])
try {
const response = await importersAPI.importSnippets(importerName, {
ids: selectedSnippetIds,
network: isNetworkAdmin(),
auto_add_tags: autoAddTags,
tag_value: autoAddTags ? tagValue : undefined
})
setImportSuccess(response.data.imported)
if (response.data.imported.length > 0) {
setSnippets([])
return true
} else {
alert(__('No snippets were imported.', 'code-snippets'))
return false
}
} catch (err) {
setImportError(err instanceof Error ? err.message : 'Unknown error')
return false
} finally {
setIsImporting(false)
}
}
const clearResults = () => {
setImportSuccess([])
setImportError(null)
}
const resetAll = () => {
setSnippets([])
clearResults()
setSnippetsError(null)
}
return {
snippets,
isLoadingSnippets,
snippetsError,
isImporting,
importError,
importSuccess,
loadSnippets,
importSnippets,
clearResults,
resetAll
}
}

View File

@@ -0,0 +1 @@
export * from './ImportForm'