Token导航 LogoToken导航TokenDH.com
待分类权限需确认github未标认证来源可访问许可证需确认审计未展示

word-processor-expert文字处理专家

Agent Skill

word-processor-expert 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

364

周安装

15

GitHub Stars

3

下载量

119
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:word-processor-expert(文字处理专家)
来源仓库:https://github.com/jmsktm/claude-settings
仓库路径:skills/word-processor-expert
安装命令:
npx skills add https://github.com/jmsktm/claude-settings --skill word-processor-expert
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/jmsktm/claude-settings --skill word-processor-expert

简介

word-processor-expert 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在开发流程中进行事项整理。

  • 适用于围绕仓库状态、代码变更或协作事项的开发管理场景。
  • 通过 GitHub API 或命令行工具集成,支持 Issue 跟踪与 PR 分析。
  • 需确认访问权限、API 限额及是否涉及敏感数据读取。
  • 建议结合项目实际情况验证操作边界,避免误改生产环境。

SKILL.md

name
word-processor-expert
description
Expert guide for building professional word processors with Tiptap/ProseMirror. Use for text editor features, document formatting, export functionality, and achieving Word/Pages/Docs feature parity.

Word Processor Expert Skill

Overview

This skill provides rapid guidance for implementing professional word processor features in id8composer using Tiptap (ProseMirror). Get you to Microsoft Word, Apple Pages, and Google Docs quality with modern web technologies.

Current Stack (id8composer)

  • Editor: Tiptap v3.10.7 (ProseMirror-based)
  • Framework: Next.js 15.5.6 + React 19
  • State: Zustand
  • Export: docx v9.5.1, jspdf v3.0.3

Quick Reference: Missing Features

❌ Not Yet Implemented

  • Text alignment (left/center/right/justify)
  • Font family/size controls
  • Heading styles (H1-H6 with styling)
  • Line spacing (1.0, 1.5, 2.0)
  • Paragraph spacing
  • Indentation controls
  • Find & Replace
  • Page breaks
  • Headers/Footers
  • Page setup (margins, orientation)
  • Proper DOCX/PDF export
  • Styles/Templates
  • Comments/Track changes

✅ Already Working

  • Bold, italic, underline
  • Lists (bullet, ordered)
  • Tables
  • Images, links
  • Color & highlight
  • Undo/Redo
  • Auto-save
  • Character/word count

Essential Tiptap Extensions

Install Missing Extensions

npm install @tiptap/extension-text-align
npm install @tiptap/extension-font-family
npm install @tiptap/extension-heading
npm install @tiptap/extension-hard-break

Text Alignment

// Add to editor extensions
import { TextAlign } from '@tiptap/extension-text-align'

const editor = useEditor({
  extensions: [
    TextAlign.configure({
      types: ['heading', 'paragraph'],
      alignments: ['left', 'center', 'right', 'justify'],
      defaultAlignment: 'left',
    }),
    // ... other extensions
  ],
})

// Toolbar buttons
<button onClick={() => editor.chain().focus().setTextAlign('left').run()}>
  <AlignLeft />
</button>
<button onClick={() => editor.chain().focus().setTextAlign('center').run()}>
  <AlignCenter />
</button>
<button onClick={() => editor.chain().focus().setTextAlign('right').run()}>
  <AlignRight />
</button>
<button onClick={() => editor.chain().focus().setTextAlign('justify').run()}>
  <AlignJustify />
</button>

Font Family & Size

import { FontFamily } from '@tiptap/extension-font-family'
import { TextStyle } from '@tiptap/extension-text-style' // Already installed

// Custom Font Size extension
import { Extension } from '@tiptap/core'

export const FontSize = Extension.create({
  name: 'fontSize',

  addOptions() {
    return {
      types: ['textStyle'],
    }
  },

  addGlobalAttributes() {
    return [
      {
        types: this.options.types,
        attributes: {
          fontSize: {
            default: null,
            parseHTML: element => element.style.fontSize.replace('px', ''),
            renderHTML: attributes => {
              if (!attributes.fontSize) return {}
              return {
                style: `font-size: ${attributes.fontSize}px`,
              }
            },
          },
        },
      },
    ]
  },

  addCommands() {
    return {
      setFontSize: (fontSize: string) => ({ chain }) => {
        return chain().setMark('textStyle', { fontSize }).run()
      },
      unsetFontSize: () => ({ chain }) => {
        return chain().setMark('textStyle', { fontSize: null }).run()
      },
    }
  },
})

// Usage in editor
const editor = useEditor({
  extensions: [
    TextStyle, // Required
    FontFamily.configure({
      types: ['textStyle'],
    }),
    FontSize,
    // ...
  ],
})

// Dropdowns in toolbar
<select onChange={(e) => editor.chain().focus().setFontFamily(e.target.value).run()}>
  <option value="Arial">Arial</option>
  <option value="Times New Roman">Times New Roman</option>
  <option value="Courier New">Courier New</option>
  <option value="Georgia">Georgia</option>
</select>

<select onChange={(e) => editor.chain().focus().setFontSize(e.target.value).run()}>
  <option value="12">12pt</option>
  <option value="14">14pt</option>
  <option value="16">16pt</option>
  <option value="18">18pt</option>
  <option value="24">24pt</option>
</select>

Line Spacing

// Custom Line Height extension
import { Extension } from '@tiptap/core'

export const LineHeight = Extension.create({
  name: 'lineHeight',

  addOptions() {
    return {
      types: ['paragraph', 'heading'],
      defaultLineHeight: '1.5',
    }
  },

  addGlobalAttributes() {
    return [
      {
        types: this.options.types,
        attributes: {
          lineHeight: {
            default: this.options.defaultLineHeight,
            parseHTML: element => element.style.lineHeight || this.options.defaultLineHeight,
            renderHTML: attributes => {
              if (!attributes.lineHeight) return {}
              return { style: `line-height: ${attributes.lineHeight}` }
            },
          },
        },
      },
    ]
  },

  addCommands() {
    return {
      setLineHeight: (lineHeight: string) => ({ commands }) => {
        return this.options.types.every((type: string) =>
          commands.updateAttributes(type, { lineHeight })
        )
      },
    }
  },
})

// Toolbar dropdown
<select onChange={(e) => editor.chain().focus().setLineHeight(e.target.value).run()}>
  <option value="1.0">Single</option>
  <option value="1.15">1.15</option>
  <option value="1.5">1.5</option>
  <option value="2.0">Double</option>
</select>

Indentation

// Install @tiptap/extension-indent if available, or create custom
export const Indent = Extension.create({
  name: 'indent',

  addOptions() {
    return {
      types: ['paragraph', 'heading'],
      minIndent: 0,
      maxIndent: 10,
    }
  },

  addGlobalAttributes() {
    return [
      {
        types: this.options.types,
        attributes: {
          indent: {
            default: 0,
            parseHTML: element => {
              const indent = element.style.paddingLeft
              return indent ? parseInt(indent) / 40 : 0
            },
            renderHTML: attributes => {
              if (!attributes.indent) return {}
              return { style: `padding-left: ${attributes.indent * 40}px` }
            },
          },
        },
      },
    ]
  },

  addCommands() {
    return {
      indent: () => ({ commands, state }) => {
        const { indent = 0 } = state.selection.$from.node().attrs
        if (indent >= this.options.maxIndent) return false
        return this.options.types.every((type: string) =>
          commands.updateAttributes(type, { indent: indent + 1 })
        )
      },
      outdent: () => ({ commands, state }) => {
        const { indent = 0 } = state.selection.$from.node().attrs
        if (indent <= this.options.minIndent) return false
        return this.options.types.every((type: string) =>
          commands.updateAttributes(type, { indent: indent - 1 })
        )
      },
    }
  },

  addKeyboardShortcuts() {
    return {
      Tab: () => this.editor.commands.indent(),
      'Shift-Tab': () => this.editor.commands.outdent(),
    }
  },
})

// Toolbar buttons
<button onClick={() => editor.chain().focus().indent().run()}>
  <IndentIncrease />
</button>
<button onClick={() => editor.chain().focus().outdent().run()}>
  <IndentDecrease />
</button>

Page Breaks

// Custom Page Break node
import { Node, mergeAttributes } from '@tiptap/core'

export const PageBreak = Node.create({
  name: 'pageBreak',
  group: 'block',
  parseHTML() {
    return [{ tag: 'div.page-break' }]
  },
  renderHTML({ HTMLAttributes }) {
    return ['div', mergeAttributes(HTMLAttributes, { class: 'page-break' }), ['hr']]
  },
  addCommands() {
    return {
      setPageBreak: () => ({ commands }) => {
        return commands.insertContent({ type: this.name })
      },
    }
  },
})

// CSS for page breaks
/* styles/editor.css */
.page-break {
  page-break-after: always;
  break-after: page;
  margin: 2rem 0;
  border: none;
  border-top: 2px dashed #ccc;
  text-align: center;
}

.page-break::after {
  content: "Page Break";
  display: inline-block;
  position: relative;
  top: -0.7em;
  padding: 0 1em;
  background: white;
  color: #999;
  font-size: 0.8em;
}

// Toolbar button
<button onClick={() => editor.chain().focus().setPageBreak().run()}>
  Insert Page Break
</button>

Find & Replace

'use client'
import { useState } from 'react'

export function FindReplace({ editor }: { editor: Editor }) {
  const [searchTerm, setSearchTerm] = useState('')
  const [replaceTerm, setReplaceTerm] = useState('')
  const [caseSensitive, setCaseSensitive] = useState(false)

  const findNext = () => {
    const content = editor.getText()
    const flags = caseSensitive ? 'g' : 'gi'
    const regex = new RegExp(searchTerm, flags)
    const matches = [...content.matchAll(regex)]

    if (matches.length > 0) {
      // Highlight first match
      const match = matches[0]
      // Implementation: Use Tiptap's TextSelection to highlight
    }
  }

  const replaceNext = () => {
    const { from, to } = editor.state.selection
    const selectedText = editor.state.doc.textBetween(from, to)

    if (selectedText === searchTerm || (!caseSensitive && selectedText.toLowerCase() === searchTerm.toLowerCase())) {
      editor.chain().focus().insertContentAt({ from, to }, replaceTerm).run()
      findNext()
    }
  }

  const replaceAll = () => {
    const content = editor.getHTML()
    const flags = caseSensitive ? 'g' : 'gi'
    const regex = new RegExp(searchTerm, flags)
    const newContent = content.replace(regex, replaceTerm)
    editor.commands.setContent(newContent)
  }

  return (
    <div className="flex gap-2 p-4 border rounded">
      <input
        type="text"
        placeholder="Find"
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
        className="border px-2 py-1"
      />
      <input
        type="text"
        placeholder="Replace"
        value={replaceTerm}
        onChange={(e) => setReplaceTerm(e.target.value)}
        className="border px-2 py-1"
      />
      <label className="flex items-center gap-1">
        <input
          type="checkbox"
          checked={caseSensitive}
          onChange={(e) => setCaseSensitive(e.target.checked)}
        />
        Case sensitive
      </label>
      <button onClick={findNext} className="px-3 py-1 bg-blue-500 text-white rounded">
        Find Next
      </button>
      <button onClick={replaceNext} className="px-3 py-1 bg-blue-500 text-white rounded">
        Replace
      </button>
      <button onClick={replaceAll} className="px-3 py-1 bg-red-500 text-white rounded">
        Replace All
      </button>
    </div>
  )
}

Professional DOCX Export

import { Document, Paragraph, TextRun, HeadingLevel, AlignmentType, Packer } from 'docx'
import { saveAs } from 'file-saver'

export async function exportToDocx(editor: Editor, filename: string) {
  // Convert Tiptap JSON to DOCX structure
  const doc = new Document({
    sections: [{
      properties: {},
      children: convertTiptapToDocx(editor.getJSON()),
    }],
  })

  const blob = await Packer.toBlob(doc)
  saveAs(blob, `${filename}.docx`)
}

function convertTiptapToDocx(tiptapJson: any): Paragraph[] {
  const paragraphs: Paragraph[] = []

  tiptapJson.content?.forEach((node: any) => {
    if (node.type === 'paragraph') {
      const runs: TextRun[] = []

      node.content?.forEach((inline: any) => {
        if (inline.type === 'text') {
          runs.push(new TextRun({
            text: inline.text,
            bold: inline.marks?.some((m: any) => m.type === 'bold'),
            italics: inline.marks?.some((m: any) => m.type === 'italic'),
            underline: inline.marks?.some((m: any) => m.type === 'underline') ? {} : undefined,
            color: inline.marks?.find((m: any) => m.type === 'textStyle')?.attrs?.color?.replace('#', ''),
            size: parseInt(inline.marks?.find((m: any) => m.type === 'textStyle')?.attrs?.fontSize || '24') * 2, // Half-points
          }))
        }
      })

      paragraphs.push(new Paragraph({
        children: runs,
        alignment: getAlignment(node.attrs?.textAlign),
        spacing: {
          before: 120,
          after: 120,
          line: parseInt(node.attrs?.lineHeight || '1.5') * 240,
        },
        indent: {
          left: (node.attrs?.indent || 0) * 720, // Twips (1/20th of a point)
        },
      }))
    } else if (node.type === 'heading') {
      paragraphs.push(new Paragraph({
        text: node.content?.[0]?.text || '',
        heading: getHeadingLevel(node.attrs?.level),
        alignment: getAlignment(node.attrs?.textAlign),
      }))
    }
  })

  return paragraphs
}

function getAlignment(align: string): AlignmentType {
  switch (align) {
    case 'left': return AlignmentType.LEFT
    case 'center': return AlignmentType.CENTER
    case 'right': return AlignmentType.RIGHT
    case 'justify': return AlignmentType.JUSTIFIED
    default: return AlignmentType.LEFT
  }
}

function getHeadingLevel(level: number): HeadingLevel {
  const levels = [
    HeadingLevel.HEADING_1,
    HeadingLevel.HEADING_2,
    HeadingLevel.HEADING_3,
    HeadingLevel.HEADING_4,
    HeadingLevel.HEADING_5,
    HeadingLevel.HEADING_6,
  ]
  return levels[level - 1] || HeadingLevel.HEADING_1
}

Professional PDF Export

import jsPDF from 'jspdf'

export function exportToPdf(editor: Editor, filename: string) {
  const doc = new jsPDF({
    orientation: 'portrait',
    unit: 'pt',
    format: 'letter',
  })

  const content = editor.getHTML()

  // Convert HTML to PDF (basic approach)
  // For production, consider using html2pdf or server-side rendering
  doc.html(content, {
    callback: (doc) => {
      doc.save(`${filename}.pdf`)
    },
    margin: [72, 72, 72, 72], // 1 inch margins
    x: 72,
    y: 72,
    width: 468, // 6.5 inches at 72 DPI
    windowWidth: 816, // 8.5 inches at 96 DPI
  })
}

// Better approach: Server-side with Puppeteer
// app/api/export-pdf/route.ts
import puppeteer from 'puppeteer'

export async function POST(req: Request) {
  const { html } = await req.json()

  const browser = await puppeteer.launch()
  const page = await browser.newPage()

  await page.setContent(html, { waitUntil: 'networkidle0' })

  const pdf = await page.pdf({
    format: 'letter',
    margin: {
      top: '1in',
      right: '1in',
      bottom: '1in',
      left: '1in',
    },
    printBackground: true,
  })

  await browser.close()

  return new Response(pdf, {
    headers: {
      'Content-Type': 'application/pdf',
      'Content-Disposition': 'attachment; filename=document.pdf',
    },
  })
}

Print Layout View

// Print-friendly CSS
/* styles/print-layout.css */
@media print {
  @page {
    size: letter;
    margin: 1in;
  }

  .editor-content {
    font-family: 'Times New Roman', serif;
    font-size: 12pt;
    line-height: 1.5;
  }

  .page-break {
    page-break-after: always;
  }

  .no-print {
    display: none;
  }
}

/* Print preview mode */
.print-preview .editor-content {
  width: 8.5in;
  min-height: 11in;
  margin: 0 auto;
  padding: 1in;
  background: white;
  box-shadow: 0 0 10px rgba(0,0,0,0.1);
}

.print-preview .page {
  width: 8.5in;
  height: 11in;
  margin-bottom: 0.5in;
  background: white;
  box-shadow: 0 0 10px rgba(0,0,0,0.1);
  page-break-after: always;
}

Keyboard Shortcuts Reference

// Add to editor configuration
const editor = useEditor({
  editorProps: {
    handleKeyDown: (view, event) => {
      // Cmd/Ctrl + B: Bold
      // Cmd/Ctrl + I: Italic
      // Cmd/Ctrl + U: Underline
      // Cmd/Ctrl + E: Center align
      // Cmd/Ctrl + L: Left align
      // Cmd/Ctrl + R: Right align
      // Cmd/Ctrl + J: Justify
      // Cmd/Ctrl + F: Find
      // Cmd/Ctrl + H: Replace
      // Cmd/Ctrl + S: Save
      // Cmd/Ctrl + P: Print
      // Cmd/Ctrl + Z: Undo
      // Cmd/Ctrl + Y: Redo
      // Tab: Increase indent
      // Shift+Tab: Decrease indent

      return false // Let Tiptap handle defaults
    },
  },
})

Performance Optimization

// Virtual scrolling for large documents
import { FixedSizeList } from 'react-window'

// Debounced auto-save
import { useDebouncedCallback } from 'use-debounce'

const debouncedSave = useDebouncedCallback(
  (content) => {
    // Save to backend
    saveDocument(content)
  },
  2000 // 2 second delay
)

// Lazy load heavy extensions
const editor = useEditor({
  extensions: [
    StarterKit,
    // Conditionally load based on feature flags
    ...(features.tables ? [Table, TableRow, TableCell] : []),
    ...(features.images ? [Image] : []),
  ],
})

When to Use This Skill

Invoke this skill when you need:

  • Quick implementation of text editor features
  • Tiptap extension examples
  • Document export functionality (DOCX/PDF)
  • Formatting toolbar patterns
  • Keyboard shortcuts
  • Print layout CSS
  • Performance tips for large documents
  • Word processor feature parity

For deep architectural work, use the text-editor-architect agent instead.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.58%
按下载量换算41

Claude

30.26%
按下载量换算36

Cursor

18.04%
按下载量换算21

Gemini CLI

9.47%
按下载量换算11

安全审计

暂无安全审计结果可展示。

权限和风险

权限需确认

当前来源未能明确判断权限范围,默认进入异常复核队列。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills