From 8bba98faa5a8bb24a5485532ba7c27caef65736b Mon Sep 17 00:00:00 2001 From: Sarosh Aga Date: Fri, 3 Apr 2026 11:37:24 +0530 Subject: [PATCH 1/6] Remove Write Brief (Breve) proofreading feature from AI Assistant The Breve system provided live proofreading with spelling, complex words, long sentences, and unconfident words detection. This removes the entire feature including the sidebar UI, Redux store, format registration, nspell/crypto-js dependencies, PHP extension registration, and the product page video showcase. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../changelog/remove-breve-write-brief | 5 + .../changelog/remove-breve-write-brief | 5 + .../components/breve/breve.scss | 45 --- .../components/breve/check.svg | 3 - .../components/breve/constants.ts | 1 - .../components/breve/controls.tsx | 156 -------- .../breve/features/_features.colors.scss | 54 --- .../breve/features/complex-words/index.ts | 45 --- .../breve/features/complex-words/phrases.ts | 255 ------------ .../components/breve/features/container.ts | 17 - .../components/breve/features/events.ts | 132 ------- .../components/breve/features/index.ts | 42 -- .../breve/features/long-sentences/index.ts | 52 --- .../custom-dictionary/a8c.ts | 23 -- .../custom-dictionary/brands.ts | 345 ---------------- .../custom-dictionary/development.ts | 30 -- .../custom-dictionary/en/abbreviations.ts | 90 ----- .../custom-dictionary/en/words.ts | 8 - .../custom-dictionary/extensions.ts | 63 --- .../custom-dictionary/index.ts | 35 -- .../custom-dictionary/products.ts | 5 - .../custom-dictionary/software.ts | 54 --- .../custom-dictionary/tlds.ts | 175 --------- .../custom-dictionary/web.ts | 65 --- .../breve/features/spelling-mistakes/index.ts | 174 -------- .../breve/features/unconfident-words/index.ts | 39 -- .../components/breve/highlight/highlight.ts | 68 ---- .../components/breve/highlight/index.tsx | 370 ------------------ .../components/breve/highlight/style.scss | 181 --------- .../components/breve/index.ts | 16 - .../components/breve/store/actions.ts | 176 --------- .../components/breve/store/index.ts | 20 - .../components/breve/store/reducer.ts | 245 ------------ .../components/breve/store/selectors.ts | 68 ---- .../components/breve/types.ts | 146 ------- .../components/breve/utils/escape-regexp.ts | 3 - .../breve/utils/flesch-kincaid-utils.ts | 45 --- .../breve/utils/get-availability.ts | 63 --- .../breve/utils/get-feature-data.ts | 173 -------- .../breve/utils/get-node-text-index.ts | 15 - .../breve/utils/get-non-link-ancestor.ts | 13 - .../components/breve/utils/get-post-text.ts | 31 -- .../breve/utils/get-request-messages.ts | 34 -- .../components/breve/utils/get-target-text.ts | 21 - .../breve/utils/number-to-ordinal.ts | 12 - .../components/breve/utils/register-format.ts | 146 ------- .../breve/utils/replace-occurrence.ts | 18 - 47 files changed, 10 insertions(+), 3772 deletions(-) create mode 100644 projects/packages/my-jetpack/changelog/remove-breve-write-brief create mode 100644 projects/plugins/jetpack/changelog/remove-breve-write-brief delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/breve.scss delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/check.svg delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/constants.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/controls.tsx delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/_features.colors.scss delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/complex-words/index.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/complex-words/phrases.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/container.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/events.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/index.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/long-sentences/index.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/a8c.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/brands.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/development.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/en/abbreviations.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/en/words.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/extensions.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/index.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/products.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/software.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/tlds.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/web.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/index.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/unconfident-words/index.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/highlight.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/index.tsx delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/style.scss delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/index.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/actions.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/index.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/reducer.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/selectors.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/types.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/escape-regexp.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/flesch-kincaid-utils.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-availability.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-feature-data.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-node-text-index.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-non-link-ancestor.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-post-text.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-request-messages.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-target-text.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/number-to-ordinal.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/register-format.ts delete mode 100644 projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/replace-occurrence.ts diff --git a/projects/packages/my-jetpack/changelog/remove-breve-write-brief b/projects/packages/my-jetpack/changelog/remove-breve-write-brief new file mode 100644 index 000000000000..ffb6b2e07654 --- /dev/null +++ b/projects/packages/my-jetpack/changelog/remove-breve-write-brief @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Remove Write Brief video showcase section from the AI product page. + +AI product page: Remove Write Brief video showcase section. diff --git a/projects/plugins/jetpack/changelog/remove-breve-write-brief b/projects/plugins/jetpack/changelog/remove-breve-write-brief new file mode 100644 index 000000000000..e73230867abd --- /dev/null +++ b/projects/plugins/jetpack/changelog/remove-breve-write-brief @@ -0,0 +1,5 @@ +Significance: minor +Type: removed +Comment: Remove the Write Brief (Breve) proofreading feature from the AI Assistant. + +AI Assistant: Remove the Write Brief (Breve) proofreading feature. diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/breve.scss b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/breve.scss deleted file mode 100644 index 0a40171caaec..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/breve.scss +++ /dev/null @@ -1,45 +0,0 @@ -@use "features/features.colors"; - -.jetpack-ai-proofread { - - .components-checkbox-control { - - &__input:not(:disabled) { - - @include features.features-colors( ( "border-color" ) ); - - &:checked { - - @include features.features-colors( ( "background-color" ) ); - } - } - - &__input:disabled { - border-color: #ddd; - background-color: #ddd; - } - } - - .components-toggle-control { - color: #1e1e1e; - margin-bottom: 16px; - } - - &__help-text { - font-size: 12px; - color: #757575; - } - - .feature-checkboxes-container { - display: flex; - flex-direction: column; - gap: 12px; - } - - &__grade-level-container { - - svg { - fill: #757575; - } - } -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/check.svg b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/check.svg deleted file mode 100644 index dc5be53483e0..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/check.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/constants.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/constants.ts deleted file mode 100644 index 66613964addd..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const BREVE_FEATURE_NAME = 'jetpack-ai-breve'; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/controls.tsx b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/controls.tsx deleted file mode 100644 index 5d964fbbfd6c..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/controls.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import { useAnalytics } from '@automattic/jetpack-shared-extension-utils'; -import { store as blockEditorStore } from '@wordpress/block-editor'; -import { - BaseControl, - PanelRow, - CheckboxControl, - ToggleControl, - Card, - CardBody, - CardFooter, -} from '@wordpress/components'; -import { compose, useDebounce } from '@wordpress/compose'; -import { useDispatch, useSelect, withSelect } from '@wordpress/data'; -import { __ } from '@wordpress/i18n'; -import { useState, useEffect, useCallback } from 'react'; -import features from './features'; -import { store as breveStore } from './store'; -import calculateFleschKincaid from './utils/flesch-kincaid-utils'; -import { canWriteBriefFeatureBeEnabled } from './utils/get-availability'; -import { getPostText } from './utils/get-post-text'; -import './breve.scss'; -import type { BreveSelect } from './types'; - -export const useInit = init => { - const [ initialized, setInitialized ] = useState( false ); - - if ( ! initialized ) { - init(); - setInitialized( true ); - } -}; - -const Controls = ( { blocks, disabledFeatures } ) => { - const [ gradeLevel, setGradeLevel ] = useState< string | null >( null ); - const { toggleFeature, toggleProofread, setPopoverHover, setHighlightHover, setPopoverAnchor } = - useDispatch( 'jetpack/ai-breve' ); - const { tracks } = useAnalytics(); - - const isProofreadEnabled = useSelect( - select => ( select( 'jetpack/ai-breve' ) as BreveSelect ).isProofreadEnabled(), - [] - ); - - const updateGradeLevel = useCallback( () => { - if ( ! isProofreadEnabled ) { - return; - } - - // Get the text content from all blocks and inner blocks. - const allText = getPostText( blocks ); - - const computedGradeLevel = calculateFleschKincaid( allText ); - - const sanitizedGradeLevel = - typeof computedGradeLevel === 'number' ? computedGradeLevel.toFixed( 2 ) : null; - - setGradeLevel( sanitizedGradeLevel ); - }, [ blocks, isProofreadEnabled ] ); - - // Calculating the grade level is expensive, so debounce it to avoid recalculating it on every keypress. - const debouncedGradeLevelUpdate = useDebounce( updateGradeLevel, 250 ); - - const handleToggleFeature = useCallback( - ( feature: string ) => ( checked: boolean ) => { - tracks.recordEvent( 'jetpack_ai_breve_feature_toggle', { type: feature, on: checked } ); - toggleFeature( feature, checked ); - }, - [ tracks, toggleFeature ] - ); - - const handleAiFeedbackToggle = useCallback( () => { - tracks.recordEvent( 'jetpack_ai_breve_toggle', { on: ! isProofreadEnabled } ); - toggleProofread(); - }, [ tracks, isProofreadEnabled, toggleProofread ] ); - - useEffect( () => { - debouncedGradeLevelUpdate(); - }, [ debouncedGradeLevelUpdate ] ); - - // Update the grade level immediately on first load. - useInit( updateGradeLevel ); - - // Disable the popover when proofread or a feature is disabled. - useEffect( () => { - setPopoverHover( false ); - setHighlightHover( false ); - setPopoverAnchor( { target: null, virtual: null } ); - }, [ - setPopoverHover, - setHighlightHover, - setPopoverAnchor, - isProofreadEnabled, - disabledFeatures, - ] ); - - return ( -
- - - - - - - { isProofreadEnabled && ( - - - - -
- { features.map( - feature => - canWriteBriefFeatureBeEnabled( feature.config.name ) && ( - - ) - ) } -
-
-
- - { gradeLevel === null ? ( -

- { __( 'Write to see your grade level.', 'jetpack' ) } -

- ) : ( -
- { gradeLevel } { __( 'Reading grade score', 'jetpack' ) } -
- ) } -
-
-
- ) } -
- ); -}; - -export default compose( - withSelect( selectFn => ( { - blocks: selectFn( blockEditorStore ).getBlocks(), - disabledFeatures: ( selectFn( breveStore ) as unknown as BreveSelect ).getDisabledFeatures(), - } ) ) -)( Controls ); diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/_features.colors.scss b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/_features.colors.scss deleted file mode 100644 index 4eba89d29a64..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/_features.colors.scss +++ /dev/null @@ -1,54 +0,0 @@ -@use "sass:map"; -@use "sass:string"; - -$features-colors: ( - "complex-words": rgb(240, 184, 73), - "unconfident-words": rgb(9, 181, 133), - "long-sentences": rgb(122, 0, 223), - "spelling-mistakes": rgb(214, 54, 56), -); - -@mixin properties( $feature, $color, $properties, $opacity: false ) { - &[data-breve-type='#{$feature}'] { - - @each $property in $properties { - - @if $opacity { - #{$property}: rgba($color, $opacity); - } @else { - #{$property}: $color; - } - } - } -} - -@mixin features-colors( $properties, $opacity: false ) { - - @each $feature, $color in $features-colors { - - @include properties( $feature, $color, $properties, $opacity ); - } -} - -@mixin pulse() { - $name: jetpack-ai-breve-loading-pulse; - - animation-name: $name; - animation-duration: 1s; - animation-iteration-count: infinite; - - @keyframes #{$name} { - - 0% { - opacity: 1; - } - - 50% { - opacity: 0.3; - } - - 100% { - opacity: 1; - } - } -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/complex-words/index.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/complex-words/index.ts deleted file mode 100644 index 77abcb777a1f..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/complex-words/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -/** - * Internal dependencies - */ -import { escapeRegExp } from '../../utils/escape-regexp'; -import phrases from './phrases'; -/** - * Types - */ -import type { BreveFeatureConfig, HighlightedText } from '../../types'; - -export const dictionary = phrases; - -export const COMPLEX_WORDS: BreveFeatureConfig = { - name: 'complex-words', - title: __( 'Complex words', 'jetpack' ), - tagName: 'span', - className: 'jetpack-ai-breve__has-proofread-highlight--complex-words', - defaultEnabled: true, -}; - -const list = new RegExp( - `\\b(${ Object.keys( phrases ).map( escapeRegExp ).join( '|' ) })\\b`, - 'gi' -); - -export default function complexWords( blockText: string ): Array< HighlightedText > { - const matches = blockText.matchAll( list ); - const highlightedTexts: Array< HighlightedText > = []; - - for ( const match of matches ) { - const text = match[ 0 ].trim(); - highlightedTexts.push( { - text, - suggestion: phrases[ text ], - startIndex: match.index, - endIndex: match.index + text.length, - } ); - } - - return highlightedTexts; -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/complex-words/phrases.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/complex-words/phrases.ts deleted file mode 100644 index 36128b9fcb89..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/complex-words/phrases.ts +++ /dev/null @@ -1,255 +0,0 @@ -// All phrases need to be lowercase -const phrases = { - 'a and/or b': 'a or b or both', - 'able to': 'can', - accompany: 'go with', - accomplish: 'do', - accorded: 'given', - accordingly: 'so', - accrue: 'add', - accurate: 'correct', - activate: 'turn on', - additional: 'more', - address: 'discuss', - 'adjacent to': 'next to', - administer: 'manage', - advantageous: 'helpful', - 'adversely impact on': 'hurt', - advise: 'recommend', - 'afford an opportunity': 'allow', - aircraft: 'plane', - allocate: 'divide', - 'allows you to': 'lets you', - alternative: 'other', - anticipate: 'expect', - 'a number of': 'some', - apparent: 'clear', - appreciable: 'many', - approximate: 'about', - 'arrive onboard': 'arrive', - 'as a means of': 'to', - ascertain: 'find out', - assist: 'help', - 'associated with': 'part of', - attain: 'meet', - attempt: 'try', - 'at the present time': 'now', - begin: 'start', - benefit: 'help', - 'by means of': 'by', - cannot: "can't", - capability: 'ability', - caveat: 'warning', - 'close proximity': 'near', - 'combat environment': 'combat', - combined: 'joint', - complete: 'finish', - 'comply with': 'follow', - component: 'part', - comprise: 'form', - concerning: 'about', - configure: 'set up', - consequently: 'so', - consolidate: 'combine', - constitutes: 'is', - contains: 'has', - convene: 'meet', - credentials: 'username and password', - currently: 'now', - customizations: 'changes', - customize: 'edit', - deactivate: 'turn off', - deem: 'consider', - delete: 'cut', - demonstrate: 'show', - depart: 'leave', - designate: 'appoint', - desire: 'want', - determine: 'decide', - disable: 'turn off', - disclose: 'show', - discontinue: 'stop', - display: 'show', - disseminate: 'give', - 'due to the fact that': 'since', - 'due to the fact': 'since', - 'during the period': 'during', - 'e.g.': 'like', - 'effect modifications': 'make changes', - elect: 'choose', - eliminate: 'cut', - employ: 'use', - enable: 'turn on', - 'enables you to': 'lets you', - encounter: 'meet', - endeavor: 'try', - ensure: 'make sure', - enumerate: 'count', - equipments: 'equipment', - equitable: 'fair', - establish: 'prove', - evidenced: 'showed', - evident: 'clear', - exhibit: 'show', - expedite: 'speed up', - expeditious: 'fast', - expend: 'spend', - expertise: 'ability', - expiration: 'end', - facilitate: 'help', - 'failed to': "didn't", - feasible: 'workable', - females: 'women', - finalize: 'finish', - following: 'next', - 'for a period of': 'for', - 'for example,______etc.': 'for example', - forfeit: 'lose', - forward: 'send', - frequently: 'often', - function: 'role', - furnish: 'give', - 'gives you the ability to': 'lets you', - 'has a requirement for': 'needs', - 'he or she': 'they', - herein: 'here', - heretofore: 'until now', - herewith: 'below', - 'his or her': 'their', - however: 'but', - identical: 'same', - identify: 'find', - immediately: 'at once', - impacted: 'affected', - 'in a timely manner': 'on time', - 'in accordance with': 'by', - 'in addition': 'also', - 'in an effort to': 'to', - 'in conjunction with': 'at the same time', - 'in lieu of': 'instead of', - 'in order that': 'for', - 'in order to': 'to', - 'in regard to': 'about', - 'in relation to': 'about', - 'in the amount of': 'for', - 'in the event of': 'if', - 'in the near future': 'soon', - 'in view of': 'since', - 'in view of the above': 'so', - 'inasmuch as': 'since', - inception: 'start', - 'incumbent upon': 'must', - indicate: 'show', - indication: 'sign', - initial: 'first', - initiate: 'start', - input: 'enter', - 'interpose no objection': "don't object", - 'is applicable to': 'applies to', - 'is authorized to': 'may', - 'is in consonance with': 'agrees with', - 'it appears': 'seems', - liaison: 'discussion', - 'limited number': 'limits', - magnitude: 'size', - maintain: 'keep', - maximum: 'most', - methodology: 'method', - methods: 'ways', - minimize: 'decrease', - minimum: 'least', - modify: 'change', - monitor: 'check', - necessitate: 'need', - notify: 'tell', - 'not later than 10 May': 'by 10 May', - 'not later than 1600': 'by 1600', - notwithstanding: 'still', - numerous: 'many', - objective: 'aim', - obligate: 'bind', - observe: 'see', - operate: 'run', - optimization: 'improvement', - optimize: 'improve', - optimum: 'best', - option: 'choice', - parameters: 'limits', - participate: 'take part', - perform: 'do', - permit: 'let', - 'pertaining to': 'about', - portion: 'part', - possess: 'have', - practicable: 'practical', - preceding: 'before', - preclude: 'prevent', - present: 'show', - previous: 'earlier', - previously: 'before', - prioritize: 'rank', - 'prior to': 'before', - proceed: 'do', - proficiency: 'skill', - promulgate: 'issue', - provide: 'give', - 'provided that': 'if', - 'provides guidance for': 'guides', - purchase: 'buy', - 'pursuant to': 'by', - receive: 'get', - reflect: 'show', - regarding: 'about', - 'relative to': 'about', - relocate: 'move', - remain: 'stay', - remainder: 'rest', - remuneration: 'pay', - render: 'give', - represents: 'is', - request: 'ask', - require: 'must', - 'required to': 'need to', - requirement: 'need', - reside: 'live', - retain: 'keep', - selection: 'choice', - 'set forth in': 'in', - 'similar to': 'like', - simultaneously: 'at the same time', - solicit: 'ask for', - 'state-of-the-art': 'latest', - subject: 'the', - submit: 'send', - subsequent: 'later', - subsequently: 'after', - substantial: 'large', - 'such as': 'like', - sufficient: 'enough', - terminate: 'end', - 'the system': 'we', - 'the undersigned': 'I', - therefore: 'so', - therein: 'there', - thereof: 'its', - timely: 'prompt', - 'to be able to': 'to', - transaction: 'order', - transmit: 'send', - 'unable to': "can't", - 'under the provisions of': 'under', - 'until such time as': 'until', - utilize: 'use', - url: 'link', - validate: 'confirm', - viable: 'workable', - vice: 'instead of', - warrant: 'permit', - whereas: 'since', - 'with reference to': 'about', - 'with the exception of': 'except for', - witnessed: 'saw', - 'x and/or y': 'x, y, or both', -}; - -export default phrases; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/container.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/container.ts deleted file mode 100644 index cf32eec5140f..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/container.ts +++ /dev/null @@ -1,17 +0,0 @@ -export default function getContainer() { - // Find the iframe by name attribute - const iframe = document.querySelector( 'iframe[name="editor-canvas"]' ) as HTMLIFrameElement; - - // Get the document inside the iframe - const iframeDocument = iframe?.contentDocument || iframe?.contentWindow?.document; - - // Find the container within the iframe or fall back to the main document - const container = - ( iframeDocument?.body as HTMLBodyElement ) || - ( document.querySelector( '.edit-post-visual-editor > div' ) as HTMLDivElement ); - - // Determine if the element is iframed - const isIframed = !! iframe; - - return { foundContainer: container, foundIframe: isIframed }; -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/events.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/events.ts deleted file mode 100644 index 7de00cb1015a..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/events.ts +++ /dev/null @@ -1,132 +0,0 @@ -/** - * External dependencies - */ -import { showAiAssistantSection } from '@automattic/jetpack-ai-client'; -import { dispatch, select } from '@wordpress/data'; -/** - * Internal dependencies - */ -import { store as breveStore } from '../store'; -import getContainer from './container'; -import { LONG_SENTENCES } from './long-sentences'; -import features from './index'; -/** - * Types - */ -import type { BreveDispatch, Anchor, BreveSelect } from '../types'; - -let highlightTimeout: number; -let anchorTimeout: number; - -let isFirstHover = ! localStorage.getItem( 'jetpack-ai-breve-first-hover' ); - -function getHighlightEl( el: HTMLElement | null ) { - if ( el === document.body || el === null ) { - return null; - } - - const breveType = el.getAttribute( 'data-breve-type' ); - const featureTypes: Array< string | null > = features.map( ( { config } ) => config.name ); - - if ( ! featureTypes.includes( breveType ) ) { - return getHighlightEl( el.parentElement ); - } - - return el; -} - -async function handleMouseEnter( e: MouseEvent ) { - if ( isFirstHover ) { - await showAiAssistantSection(); - - isFirstHover = false; - localStorage.setItem( 'jetpack-ai-breve-first-hover', 'false' ); - - const isSmall = window.innerWidth < 600; - - // Do not show popover on small screens on first hover, as the sidebar will open - if ( isSmall ) { - return; - } - } - - clearTimeout( highlightTimeout ); - clearTimeout( anchorTimeout ); - - const breveSelect = select( breveStore ) as unknown as BreveSelect; - - anchorTimeout = setTimeout( () => { - const isPopoverHover = breveSelect.isPopoverHover(); - - if ( isPopoverHover ) { - return; - } - - const el = getHighlightEl( e.target as HTMLElement ); - - if ( ! el ) { - return; - } - - let virtual = el; - const shouldPointToCursor = el.getAttribute( 'data-breve-type' ) === LONG_SENTENCES.name; - - if ( shouldPointToCursor ) { - const rect = el.getBoundingClientRect(); - const diff = e.clientY - Math.floor( rect.top ); - const offset = diff === 0 ? 10 : 0; - - virtual = { - getBoundingClientRect() { - return { - top: e.clientY + offset, - left: e.clientX, - bottom: e.clientY, - right: e.clientX, - width: 0, - height: 0, - x: e.clientX, - y: e.clientY, - } as DOMRect; - }, - contextElement: e.target as HTMLElement, - } as unknown as HTMLElement; - } - - ( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).setHighlightHover( true ); - ( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).setPopoverAnchor( { - target: el, - virtual: virtual, - } as Anchor ); - }, 500 ); -} - -function handleMouseLeave() { - clearTimeout( highlightTimeout ); - clearTimeout( anchorTimeout ); - - highlightTimeout = setTimeout( () => { - ( dispatch( 'jetpack/ai-breve' ) as BreveDispatch ).setHighlightHover( false ); - }, 100 ); -} - -export default function registerEvents( clientId: string ) { - const { foundContainer: container } = getContainer(); - const id = `block-${ clientId }`; - const block = container?.querySelector?.( `#${ id }` ); - - features.forEach( ( { config } ) => { - const items: NodeListOf< HTMLElement > | undefined = block?.querySelectorAll?.( - `[data-breve-type='${ config.name }']` - ); - - if ( items && items?.length > 0 ) { - items.forEach( highlightEl => { - highlightEl?.removeEventListener?.( 'mouseover', handleMouseEnter ); - highlightEl?.addEventListener?.( 'mouseover', handleMouseEnter ); - highlightEl?.removeEventListener?.( 'mouseleave', handleMouseLeave ); - highlightEl?.addEventListener?.( 'mouseleave', handleMouseLeave ); - } ); - } - } ); -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/index.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/index.ts deleted file mode 100644 index 698c1fcb282b..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -/** - * Features - */ -import complexWords, { COMPLEX_WORDS, dictionary as dicComplex } from './complex-words'; -import longSentences, { LONG_SENTENCES } from './long-sentences'; -import spellingMistakes, { SPELLING_MISTAKES } from './spelling-mistakes'; -import unconfidentWords, { UNCONFIDENT_WORDS } from './unconfident-words'; -/** - * Types - */ -import type { BreveFeature } from '../types'; - -// Breve Highlights Features -const features: Array< BreveFeature > = [ - { - config: SPELLING_MISTAKES, - highlight: spellingMistakes, - description: __( 'Fix spelling mistakes.', 'jetpack' ), - }, - { - config: COMPLEX_WORDS, - highlight: complexWords, - dictionary: dicComplex, - description: __( 'Use simple, direct words.', 'jetpack' ), - }, - { - config: LONG_SENTENCES, - highlight: longSentences, - description: __( 'Long sentences are hard to read.', 'jetpack' ), - }, - { - config: UNCONFIDENT_WORDS, - highlight: unconfidentWords, - description: __( 'Remove weasel words.', 'jetpack' ), - }, -]; - -export default features; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/long-sentences/index.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/long-sentences/index.ts deleted file mode 100644 index 5efbb9cac88f..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/long-sentences/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -/** - * Internal dependencies - */ -import { escapeRegExp } from '../../utils/escape-regexp'; -/** - * Types - */ -import type { BreveFeatureConfig, HighlightedText } from '../../types'; - -export const LONG_SENTENCES: BreveFeatureConfig = { - name: 'long-sentences', - title: __( 'Long sentences', 'jetpack' ), - tagName: 'span', - className: 'jetpack-ai-breve__has-proofread-highlight--long-sentences', - defaultEnabled: true, -}; - -const sentenceRegex = /[^\s][^.!?]+[.!?]+/g; - -export default function longSentences( text: string ): Array< HighlightedText > { - const highlightedTexts: Array< HighlightedText > = []; - - const sentenceMatches = text.match( sentenceRegex ); - - if ( ! sentenceMatches ) { - return highlightedTexts; - } - - const sentences = [ - // Unique sentences with more than 20 words - ...new Set( sentenceMatches.filter( sentence => sentence.split( /\s+/ ).length > 20 ) ), - ]; - - sentences.forEach( sentence => { - const regex = new RegExp( escapeRegExp( sentence ), 'gi' ); - const matches = text.matchAll( regex ); - - for ( const match of matches ) { - highlightedTexts.push( { - text: sentence, - startIndex: match.index, - endIndex: match.index + sentence.length, - } ); - } - } ); - - return highlightedTexts; -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/a8c.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/a8c.ts deleted file mode 100644 index 9ec6f8d8c97e..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/a8c.ts +++ /dev/null @@ -1,23 +0,0 @@ -export default ` -Akismet -Automattic -Automattician -Automatticians -bbPress -BuddyPress -Cloudup -Crowdsignal -Gravatar -Jetpack -Longreads -Mullenweg -Newspack -Pressable -Sensei -Simplenote -Tumblr -VideoPress -WooCommerce -WordCamp -WPScan -`; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/brands.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/brands.ts deleted file mode 100644 index 11ba20c39060..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/brands.ts +++ /dev/null @@ -1,345 +0,0 @@ -const food = `Barilla -Burger -Coca -Cola -Danone -Dominos -Esso -Fanta -Heineken -HelloFresh -Häagen -Dazs -Kelloggs -Milka -Nestlé -Nutella -Pepsi -Starbucks -King -McDonalds -Kat -Sprite -DrPepper -Absolut -`; - -const financial = `Amex -Bradesco -Citi -Goldman -Sachs -Lloyds -MercadoPago -Nubank -PagSeguro -PayPal -Revolut -Santander -Square -Stripe -Venmo -Visa -Mastercard -PicPay -Allianz -AXA -BlackRock -Schwab -`; - -const automotive = `Audi -BMW -Benz -Ford -Hyundai -Kia -Lamborghini -Land -Rover -Mercedes -Mitsubishi -Nissan -Peugeot -Renault -Skoda -Subaru -Tata -Toyota -Volkswagen -Volvo -Honda -Tesla -Ferrari -Porsche -Maserati -Bentley -Rolls -Royce -Jaguar -Aston -Martin -McLaren -Bugatti -`; - -const electronics = `Acer -Dyson -GoPro -HP -HPE -Huawei -JBL -Lenovo -LG -Macintosh -Nikon -Nokia -Philips -Samsung -Sony -Xiaomi -Nintendo -Asus -Fujifilm -Fitbit -Garmin -`; - -const fashion = `Adidas -Asics -Balenciaga -Benetton -Cartier -Fila -Gucci -Hermès -Hublot -Lacoste -Louis -Vuitton -Mango -Nike -Puma -RayBan -Reebok -Rolex -Swatch -Zalando -Zara -Giorgio -Armani -Versace -Prada -Fendi -Burberry -Ralph -Lauren -Tommy -Hilfiger -Calvin -Klein -Levi -Strauss -Timberland -Converse -Vans -Crocs -Ugg -Timberland -`; - -const travel = `AirFrance -Booking -Expedia -Hilton -Hyatt -KLM -Marriott -Tripadvisor -Airbnb -`; - -const media = `BBC -Disney -HBO -Netflix -Spotify -Twitch -YouTube -Hulu -Patreon -Crunchyroll -Funimation -`; - -const pharma = `Bayer -Novartis -Pfizer -Roche -Sanofi -GSK -AstraZeneca -Novavax -Moderna -BioNTech -Sanofi -GSK -`; - -const commerce = `Alibaba -Amazon -Carrefour -Etsy -Rakuten -Temu -Walmart -eBay -Zalando -BestBuy -HomeDepot -Ikea -`; - -const cosmetics = `Chanel -Dior -Estée -Lauder -L'Oréal -Maybelline -Nivea -Sephora -Clinique -Lancôme -Givenchy -Estée -`; - -const consumer = `3M -Procter -Gamble -Unilever -Pritt -Bristol -Joma -`; - -const tech = `Twilio -DigitalOcean -ClickUp -Fastly -Auth0 -Algolia -OpenAI -GoPro -JetBrains -Meta -Apple -Google -Facebook -DuckDuckGo -Instagram -LinkedIn -Vercel -Calendly -Tencent -Adobe -IBM -Kaspersky -Microsoft -Opera -Oracle -Squarespace -HubSpot -Zapier -Coinbase -Binance -Robinhood -Activision -Ubisoft -Rockstar -`; - -const logistics = `DoorDash -Uber -Eternal -Grab -Swiggy -Deliveroo -HelloFresh -Wolt -Bolt -Lyft -DHL -FedEx -Postmates -Instacart -Shipt -`; - -const dating = `Tinder -Bumble -Badoo -OkCupid -Hinge -Match -Grindr -`; - -const education = `Duolingo -Grammarly -Udemy -Petrobras -Shell -edX -Skillshare -Pluralsight -Codecademy -`; - -const commodities = `Aramco -Chevron -Ecopetrol -Exxon -`; - -const services = `Deloitte -JLL -Salesforce -SAP -Vodafone -`; - -const manufacturing = `Bridgestone -Caterpillar -Siemens -BASF -`; - -export default [ - food, - financial, - automotive, - electronics, - fashion, - travel, - media, - pharma, - commerce, - cosmetics, - consumer, - tech, - logistics, - dating, - education, - commodities, - services, - manufacturing, -] - .flatMap( block => - block - .trim() - .split( '\n' ) - .filter( line => line.trim() !== '' ) - ) - .join( '\n' ); diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/development.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/development.ts deleted file mode 100644 index 13c90b4e9a4e..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/development.ts +++ /dev/null @@ -1,30 +0,0 @@ -export default `Fortran -Joomla -Laravel -Vue -Webpack -WebSocket -npm -pnpm -ESLint -Supabase -GraphQL -gRPC -DALL -CodeSandbox -Codespaces -TravisCI -CircleCI -Kubernetes -Prismic -SendGrid -Vultr -Vite -Dockerfile -Makefile -makefile -JSON -YAML -YML -CSV -`; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/en/abbreviations.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/en/abbreviations.ts deleted file mode 100644 index 993e4c3f553b..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/en/abbreviations.ts +++ /dev/null @@ -1,90 +0,0 @@ -export default `Ad -ASAP -DIY -ETA -FYI -Info -Lab -Math -Photo -RSVP -TBD -TBA -TGIF -AMA -BFF -BRB -BTW -DM -FOMO -ICYMI -IDK -IMO -IRL -IYKYK -LOL -NSFW -OMG -ROFL -SMH -TTYL -WTG -YOLO -B2B -B2C -CEO -CFO -EOD -EOY -FY -HR -KPI -NDA -PR -ROI -SEO -SME -Stats -YOY -API -CSS -HTML -HTTP -HTTPS -IoT -IP -SaaS -URL -UX -UI -VPN -Wi -Fi -ACT -BA -BS -CEFR -ESL -GPA -IELTS -LMS -MA -MOOC -MSc -PGCE -PhD -PGDip -STEM -TOEFL -ADHD -AIDS -BPM -DNA -HIV -ICU -MD -RNA -GBP -etc -Eg -`; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/en/words.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/en/words.ts deleted file mode 100644 index 0975b5abdd2f..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/en/words.ts +++ /dev/null @@ -1,8 +0,0 @@ -export default `config -microservice -microservices -frontend -backend -integrations -influencer -`; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/extensions.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/extensions.ts deleted file mode 100644 index 68b8e26ca28d..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/extensions.ts +++ /dev/null @@ -1,63 +0,0 @@ -export default ` -js -json -yaml -tsx -jsx -yml -md -css -scss -html -xml -csv -sql -py -rb -php -cpp -hpp -ini -conf -env -dockerfile -makefile -gradle -toml -pdf -svg -png -jpg -jpeg -gif -mp4 -mp3 -webm -ogg -docx -xlsx -pptx -txt -tex -avi -bat -bmp -dll -exe -flv -iso -jpg -mov -mpeg -msi -ogg -png -rar -sys -tif -tmp -wav -wma -wmv -xls -`; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/index.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/index.ts deleted file mode 100644 index fe079b8bc8dd..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Internal dependencies - */ -import a8c from './a8c'; -import brands from './brands'; -import development from './development'; -import abbreviations from './en/abbreviations'; -import words from './en/words'; -import extensions from './extensions'; -import products from './products'; -import software from './software'; -import tlds from './tlds'; -import web from './web'; - -const fullDictionary = [ - a8c, - brands, - development, - extensions, - products, - software, - tlds, - web, - abbreviations, - words, -] - .flatMap( block => - block - .trim() - .split( '\n' ) - .filter( line => line.trim() !== '' ) - ) - .join( '\n' ); - -export default fullDictionary; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/products.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/products.ts deleted file mode 100644 index b6ba9bb8defd..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/products.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default `iPhone -iPad -MacBook -Macintosh -`; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/software.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/software.ts deleted file mode 100644 index d39e04f839e4..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/software.ts +++ /dev/null @@ -1,54 +0,0 @@ -export default ` -Audacity -Blender -DaVinci -Resolve -Dreamweaver -Dropbox -FileZilla -GarageBand -InDesign -Inkscape -IntelliJ -Jira -LibreOffice -Lightroom -OneNote -Photoshop -Postman -PowerShell -Premiere -PyCharm -Replit -Symfony -VSCode -VirtualBox -WebStorm -Wireshark -Xcode -XD -Zsh -Contentful -MacOS -macOS -Windows -Linux -Android -iOS -iCloud -iMessage -iMovie -NetBeans -VLC -AVG -Avast -Bitdefender -Brave -Chrome -Firefox -Minecraft -Signal -Steam -Zotero -QuickBooks -`; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/tlds.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/tlds.ts deleted file mode 100644 index b53f94274d41..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/tlds.ts +++ /dev/null @@ -1,175 +0,0 @@ -export default ` -ae -af -ag -ai -al -ao -aq -ar -au -az -ba -bb -bd -bg -bh -bj -bm -bn -bo -bq -br -bs -bt -bv -bw -bz -cd -ci -cn -cr -cv -cx -cy -cz -de -dev -dj -dk -dm -ec -edu -ee -eg -et -eu -fi -fj -fk -fm -fo -ga -gb -gd -ge -gf -gg -gh -gi -gl -gn -gp -gq -gu -gw -gy -hk -hm -hn -hu -ie -il -im -io -iq -ir -je -jm -jo -jp -ke -kh -ki -kp -kr -ky -kz -lc -li -lk -lr -lt -lu -lv -ly -mc -md -mh -mk -mn -mq -mr -mv -mw -mx -mz -na -nc -ne -nf -ng -ni -nl -np -nr -nz -pe -ph -pn -ps -pw -py -qa -ro -ru -rw -sa -sb -sc -sd -se -sg -si -sj -sk -sl -sm -sn -sr -ss -sv -sx -sy -sz -tc -td -tf -tg -th -tj -tk -tl -tm -tt -tv -tz -ua -ug -uk -uy -uz -va -vc -ve -vg -vn -vu -wf -ws -xyz -yt -za -zm -zw -`; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/web.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/web.ts deleted file mode 100644 index c50f180ae567..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/custom-dictionary/web.ts +++ /dev/null @@ -1,65 +0,0 @@ -export default ` -Asana -Alexa -Basecamp -Bluesky -Coursera -Douyin -Fiverr -Figma -GitHub -GitLab -Gumroad -HackerNews -Mastodon -Messenger -Nextdoor -OneDrive -Outlook -Pinterest -ProductHunt -Quora -Reddit -Slack -Snapchat -StackOverflow -Substack -Telegram -Threads -TikTok -Trello -Tripadvisor -Twitter -Upwork -Vimeo -VK -VKontakte -WeChat -Weibo -WhatsApp -Wix -X -Xiaohongshu -Yahoo -YouTube -Zoom -Netlify -Gmail -Mailchimp -Canva -Kickstarter -Shopify -Bitbucket -ChatGPT -Cloudflare -Cloudinary -QQ -LINE -KakaoTalk -Odnoklassniki -Bing -Discord -Hotmail -Ebay -Groupon -`; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/index.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/index.ts deleted file mode 100644 index 267e049b9385..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/spelling-mistakes/index.ts +++ /dev/null @@ -1,174 +0,0 @@ -/** - * External dependencies - */ -import { dispatch } from '@wordpress/data'; -import { __ } from '@wordpress/i18n'; -import debugFactory from 'debug'; -import nspell from 'nspell'; -/** - * Internal dependencies - */ -import getFeatureData from '../../utils/get-feature-data'; -import customDictionary from './custom-dictionary'; -/** - * Types - */ -import type { BreveFeatureConfig, HighlightedText, SpellChecker, BreveDispatch } from '../../types'; - -const debug = debugFactory( 'jetpack-ai-breve:spelling-mistakes' ); - -export const SPELLING_MISTAKES: BreveFeatureConfig = { - name: 'spelling-mistakes', - title: __( 'Spelling mistakes', 'jetpack' ), - tagName: 'span', - className: 'jetpack-ai-breve__has-proofread-highlight--spelling-mistakes', - defaultEnabled: true, -}; - -const spellCheckers: { [ key: string ]: SpellChecker } = {}; - -export const getSpellChecker = ( { language = 'en' }: { language?: string } = {} ) => { - if ( spellCheckers[ language ] ) { - return spellCheckers[ language ]; - } - - // Cannot await here as the Rich Text function needs to be synchronous. - // Load of the dictionary in the background if necessary and re-trigger the highlights later. - const spellingContext = getFeatureData( { feature: SPELLING_MISTAKES.name, language } ); - - if ( ! spellingContext ) { - return null; - } - - const { affix, dictionary } = spellingContext; - const spellChecker = nspell( affix, dictionary ) as unknown as SpellChecker; - - // Get the exceptions from the local storage - const exceptions: string[] = Array.from( - new Set( - JSON.parse( - localStorage.getItem( `jetpack-ai-breve-spelling-exceptions-${ language }` ) as string - ) || [] - ) - ); - exceptions.forEach( exception => spellChecker.add( exception ) ); - - // Add the custom dictionary - spellChecker.personal( customDictionary ); - - spellCheckers[ language ] = spellChecker; - - return spellCheckers[ language ]; -}; - -export const addTextToDictionary = ( - text: string, - { language = 'en' }: { language?: string } = {} -) => { - const spellChecker = getSpellChecker( { language } ); - const { reloadDictionary } = dispatch( 'jetpack/ai-breve' ) as BreveDispatch; - - if ( ! spellChecker ) { - return; - } - - try { - // Save the new exception to the local storage - const current = new Set( - JSON.parse( - localStorage.getItem( `jetpack-ai-breve-spelling-exceptions-${ language }` ) as string - ) || [] - ); - - current.add( text ); - - localStorage.setItem( - `jetpack-ai-breve-spelling-exceptions-${ language }`, - JSON.stringify( Array.from( current ) ) - ); - } catch ( error ) { - debug( 'Failed to add text to the dictionary', error ); - return; - } - - // Recompute the spell checker on the next call - delete spellCheckers[ language ]; - - reloadDictionary(); - - debug( 'Added text to the dictionary', text ); -}; - -export const suggestSpellingFixes = ( - text: string, - { language = 'en' }: { language?: string } = {} -) => { - const spellChecker = getSpellChecker( { language } ); - - if ( ! spellChecker || ! text ) { - return []; - } - - // capital_P_dangit - if ( text.toLocaleLowerCase() === 'wordpress' ) { - return [ 'WordPress' ]; - } - - const suggestions = spellChecker.suggest( text ); - - return suggestions; -}; - -export default function spellingMistakes( text: string ): Array< HighlightedText > { - const highlightedTexts: Array< HighlightedText > = []; - const spellChecker = getSpellChecker(); - - if ( ! spellChecker ) { - return highlightedTexts; - } - - // Regex to match words, including contractions, hyphenated words, and words separated by slashes - // \p{L} matches any Unicode letter in any language - // \p{M} matches any Unicode mark (combining characters) - // The regex has three main parts: - // 1. [@#+$/]{0,1} - Optionally matches a single special character at the start - // 2. [\p{L}\p{M}\p{N}'’-] - Matches one or more letters, marks, numbers, apostrophes, or hyphens - // 3. (?:\/[\p{L}\p{M}\p{N}'’-]+)* - Optionally matches additional parts separated by slashes - const wordRegex = new RegExp( /[@#+$/]{0,1}[\p{L}\p{M}\p{N}'’-]+(?:\/[\p{L}\p{M}\p{N}'’-]+)*/gu ); - const matches = Array.from( text.matchAll( wordRegex ) ); - - matches.forEach( match => { - const word = match[ 0 ]; - const startIndex = match.index as number; - - // Skip words that start with special characters - if ( [ '@', '#', '+', '$', '/' ].indexOf( word[ 0 ] ) !== -1 ) { - return; - } - - // Skip anything that is a valid number - if ( ! isNaN( Number( word ) ) ) { - return; - } - - // Split words by hyphens and slashes - const subWords = word.split( /[-/]/ ); - - subWords.forEach( subWord => { - // remove single quotes from beginning/end and apostrophes from the end - subWord = subWord.replace( /^'+|['’]+$/g, '' ); - - if ( ! spellChecker.correct( subWord ) ) { - const subWordStartIndex = startIndex + word.indexOf( subWord ); - - highlightedTexts.push( { - text: subWord, - startIndex: subWordStartIndex, - endIndex: subWordStartIndex + subWord.length, - } ); - } - } ); - } ); - - return highlightedTexts; -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/unconfident-words/index.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/unconfident-words/index.ts deleted file mode 100644 index 9e4e88bfd493..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/features/unconfident-words/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -/** - * Internal dependencies - */ -import { escapeRegExp } from '../../utils/escape-regexp'; -import getFeatureData from '../../utils/get-feature-data'; -/** - * Types - */ -import type { BreveFeatureConfig, HighlightedText } from '../../types'; - -export const UNCONFIDENT_WORDS: BreveFeatureConfig = { - name: 'unconfident-words', - title: __( 'Unconfident words', 'jetpack' ), - tagName: 'span', - className: 'jetpack-ai-breve__has-proofread-highlight--unconfident-words', - defaultEnabled: true, -}; - -export default function unconfidentWords( blockText: string ): Array< HighlightedText > { - const highlightedTexts: Array< HighlightedText > = []; - const dictionary = getFeatureData( { feature: UNCONFIDENT_WORDS.name, language: 'en' } ) ?? []; - const list = new RegExp( `\\b(${ dictionary.map( escapeRegExp ).join( '|' ) })\\b`, 'gi' ); - const matches = blockText.matchAll( list ); - - for ( const match of matches ) { - const text = match[ 0 ].trim(); - highlightedTexts.push( { - text, - startIndex: match.index, - endIndex: match.index + text.length, - } ); - } - - return highlightedTexts; -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/highlight.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/highlight.ts deleted file mode 100644 index 60ff0ceb58c7..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/highlight.ts +++ /dev/null @@ -1,68 +0,0 @@ -/** - * External dependencies - */ -import { applyFormat } from '@wordpress/rich-text'; -import md5 from 'crypto-js/md5'; -/** - * Types - */ -import type { HighlightedText } from '../types'; -import type { RichTextValue } from '@wordpress/rich-text'; - -type RichTextFormat = Parameters< typeof applyFormat >[ 1 ]; - -export type HighlightProps = { - content: RichTextValue; - type: string; - indexes: Array< HighlightedText >; - attributes?: { [ key: string ]: string }; - ignored: Array< string >; -}; - -type HighlightData = { - start: number; - end: number; - id: string; -}; - -const applyHighlightFormat = ( { - content, - type, - indexes, - attributes = {}, - ignored = [], -}: HighlightProps ): RichTextValue => { - let newContent = content; - - if ( indexes.length > 0 ) { - newContent = indexes - .map( highlightedText => { - const { startIndex, endIndex, text } = highlightedText; - const id = md5( `${ text }-${ startIndex }-${ endIndex }` ).toString(); - return { start: startIndex, end: endIndex, id } as HighlightData; - } ) - .filter( data => ! ignored.includes( data?.id ) ) - .reduce( ( acc: RichTextValue, { start, end, id }: HighlightData ) => { - const currentAttr = { ...attributes, 'data-id': id }; - - const format = { - type, - attributes: currentAttr, - } as RichTextFormat; - - return applyFormat( acc, format, start, end ); - }, content ); - } - - return newContent; -}; - -export default function highlight( { - content, - type, - indexes, - attributes, - ignored, -}: HighlightProps ) { - return applyHighlightFormat( { indexes, content, type, attributes, ignored } ); -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/index.tsx b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/index.tsx deleted file mode 100644 index 460bfee1b6cf..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/index.tsx +++ /dev/null @@ -1,370 +0,0 @@ -/** - * External dependencies - */ -import { fixes, Block, AiFeedbackThumbs, AiSVG } from '@automattic/jetpack-ai-client'; -import { useAnalytics } from '@automattic/jetpack-shared-extension-utils'; -import { rawHandler, serialize } from '@wordpress/blocks'; -import { Button, Popover, Spinner } from '@wordpress/components'; -import { useDispatch, useSelect } from '@wordpress/data'; -import { useState, useEffect } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { reusableBlock as retry } from '@wordpress/icons'; -import clsx from 'clsx'; -/** - * Internal dependencies - */ -import { BREVE_FEATURE_NAME } from '../constants'; -import features from '../features'; -import { LONG_SENTENCES } from '../features/long-sentences'; -import { - SPELLING_MISTAKES, - addTextToDictionary, - suggestSpellingFixes, -} from '../features/spelling-mistakes'; -import getTargetText from '../utils/get-target-text'; -import { numberToOrdinal } from '../utils/number-to-ordinal'; -import replaceOccurrence from '../utils/replace-occurrence'; -import './style.scss'; -/** - * Types - */ -import type { BreveDispatch, BreveSelect } from '../types'; -import type { MouseEvent } from 'react'; - -type CoreBlockEditorSelect = { - getBlock: ( clientId: string ) => Block; -}; - -// Setup the Breve highlights -export default function Highlight() { - const { - setPopoverHover, - setSuggestions, - invalidateSuggestions, - ignoreSuggestion, - invalidateSingleSuggestion, - } = useDispatch( 'jetpack/ai-breve' ) as BreveDispatch; - - const { tracks } = useAnalytics(); - const { updateBlockAttributes } = useDispatch( 'core/block-editor' ); - const { getBlock } = useSelect( select => { - const selector = select( 'core/block-editor' ) as CoreBlockEditorSelect; - - return { getBlock: selector.getBlock }; - }, [] ); - const [ spellingSuggestions, setSpellingSuggestions ] = useState< string[] >( [] ); - - const { - anchor, - virtual, - popoverOpen, - id, - feature, - blockId, - title, - loading, - suggestions, - description, - } = useSelect( select => { - const breveSelect = select( 'jetpack/ai-breve' ) as BreveSelect; - - // Popover - const isPopoverHover = breveSelect.isPopoverHover(); - const isHighlightHover = breveSelect.isHighlightHover(); - - // Anchor data - const defaultAnchor = { target: null, virtual: null }; - const { target: anchorEl, virtual: virtualEl } = - breveSelect.getPopoverAnchor() ?? defaultAnchor; - const anchorFeature = anchorEl?.getAttribute?.( 'data-breve-type' ) as string; - const anchorId = anchorEl?.getAttribute?.( 'data-id' ) as string; - const anchorBlockId = anchorEl?.getAttribute?.( 'data-block' ) as string; - - // Feature data - const featureData = features?.find?.( ftr => ftr.config.name === anchorFeature ); - const featureConfig = featureData?.config ?? { name: '', title: '' }; - const featureDescription = featureData?.description ?? ''; - const featureTitle = featureConfig?.title ?? ''; - - // Suggestions - const loadingSuggestions = breveSelect.getSuggestionsLoading( { - feature: anchorFeature, - id: anchorId, - blockId: anchorBlockId, - } ); - - const suggestionsData = breveSelect.getSuggestions( { - feature: anchorFeature, - id: anchorId, - blockId: anchorBlockId, - } ); - - return { - title: featureTitle, - description: featureDescription, - anchor: anchorEl, - virtual: virtualEl, - feature: anchorFeature, - id: anchorId, - blockId: anchorBlockId, - popoverOpen: isHighlightHover || isPopoverHover, - loading: loadingSuggestions, - suggestions: suggestionsData, - }; - }, [] ); - - const isPopoverOpen = popoverOpen && virtual; - const hasSuggestions = Boolean( suggestions?.suggestion ) || spellingSuggestions.length > 0; - - const handleMouseEnter = () => { - setPopoverHover( true ); - }; - - const handleMouseLeave = ( e: MouseEvent ) => { - e.stopPropagation(); - setPopoverHover( false ); - }; - - const handleSuggestions = () => { - const block = getBlock( blockId ); - - if ( ! block ) { - setPopoverHover( false ); - return; - } - - tracks.recordEvent( 'jetpack_ai_breve_ask', { - feature: BREVE_FEATURE_NAME, - block: block.name, - type: feature, - } ); - - const { target, text, occurrence } = getTargetText( anchor as HTMLElement ); - const ordinalOccurence = numberToOrdinal( occurrence ); - - setSuggestions( { - anchor, - id, - target, - feature, - text, - blockId, - occurrence: ordinalOccurence, - } ); - }; - - const handleApplySuggestion = () => { - const block = getBlock( blockId ); - - if ( ! block ) { - setPopoverHover( false ); - return; - } - - let render = suggestions?.html; - - // Apply known fixes for table and list-item blocks - if ( block.name === 'core/table' ) { - render = fixes.table( suggestions?.html, true, { - hasFixedLayout: block.attributes?.hasFixedLayout, - } ); - } - - if ( block.name === 'core/list-item' ) { - render = fixes.listItem( suggestions?.html, true ); - } - - const [ newBlock ] = rawHandler( { HTML: render } ); - invalidateSuggestions( blockId ); - updateBlockAttributes( blockId, newBlock.attributes ); - setPopoverHover( false ); - - tracks.recordEvent( 'jetpack_ai_breve_apply', { - feature: BREVE_FEATURE_NAME, - block: block.name, - type: feature, - } ); - }; - - const handleApplySpellingFix = ( spellingSuggestion: string ) => { - const block = getBlock( blockId ); - - if ( ! block ) { - setPopoverHover( false ); - return; - } - - const { target, occurrence } = getTargetText( anchor as HTMLElement ); - - // The serialize function returns the block's HTML with its Gutenberg comments - const html = serialize( block ); - const fixedHtml = replaceOccurrence( { - text: html, - target, - occurrence, - replacement: spellingSuggestion, - } ); - - const [ newBlock ] = rawHandler( { HTML: fixedHtml } ); - invalidateSuggestions( blockId ); - updateBlockAttributes( blockId, newBlock.attributes ); - setPopoverHover( false ); - }; - - const handleRetry = () => { - invalidateSingleSuggestion( feature, blockId, id ); - handleSuggestions(); - - tracks.recordEvent( 'jetpack_ai_breve_retry', { - feature: BREVE_FEATURE_NAME, - type: feature, - } ); - }; - - const handleIgnoreSuggestion = () => { - ignoreSuggestion( blockId, id ); - setPopoverHover( false ); - - tracks.recordEvent( 'jetpack_ai_breve_ignore', { - feature: BREVE_FEATURE_NAME, - type: feature, - } ); - }; - - const handleAddToDictionary = () => { - const { target } = getTargetText( anchor as HTMLElement ); - addTextToDictionary( target ); - - tracks.recordEvent( 'jetpack_ai_breve_add_to_dictionary', { - feature: BREVE_FEATURE_NAME, - type: feature, - word: target, - language: 'en', - } ); - }; - - useEffect( () => { - if ( feature === SPELLING_MISTAKES.name && isPopoverOpen ) { - // Get the typo - const typo = anchor?.innerText; - - if ( ! typo ) { - return; - } - - // Get the suggestions - setSpellingSuggestions( suggestSpellingFixes( typo ) ); - } else { - setSpellingSuggestions( [] ); - } - }, [ feature, isPopoverOpen, anchor ] ); - - return ( - <> - { isPopoverOpen && anchor?.parentElement && ( - -
-
-
-
-
{ title }
-
- { feature !== SPELLING_MISTAKES.name && ( -
- { hasSuggestions ? ( - - ) } - - ) } -
- ) } -
-
- { feature !== SPELLING_MISTAKES.name && hasSuggestions && ( - - ) } - - { feature === SPELLING_MISTAKES.name && - spellingSuggestions.map( spellingSuggestion => ( - - ) ) } -
-
- { feature === SPELLING_MISTAKES.name && ( - - ) } - - { feature !== SPELLING_MISTAKES.name && - ( hasSuggestions - ? __( 'Click on the suggestion to insert it.', 'jetpack' ) - : description ) } - -
- - -
- -
-
-
-
- - ) } - - ); -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/style.scss b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/style.scss deleted file mode 100644 index 976f0071dbfa..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/highlight/style.scss +++ /dev/null @@ -1,181 +0,0 @@ -@use "../features/features.colors"; - -[class^="jetpack-ai-breve__has-proofread-highlight"] { - transition: background-color; - transition-duration: 0.3s; - border-bottom: 3px solid; - - @include features.features-colors( ( "border-bottom-color" ) ); - - &.jetpack-ai-breve__is-loading { - - @include features.pulse(); - } - - &.jetpack-ai-breve__highlight-hovered { - - @include features.features-colors( ( "background-color" ), 0.2 ); - } -} - -.jetpack-ai-breve__highlight-popover { - color: #000; - cursor: default; - font-size: 13px; - font-style: normal; - font-weight: 400; - line-height: 18px; - width: auto; - - .jetpack-ai-breve__highlight-content { - align-items: center; - display: flex; - flex-direction: column; - - &.jetpack-ai-breve__has-suggestions { - align-items: flex-start; - - .jetpack-ai-breve__suggestions-container { - max-height: calc(200px - 32px); // 32px is the height of the helper buttons wrapper - overflow-y: auto; - overflow-x: hidden; - padding: 3px 0; // Space for the focus highlight - } - } - - .jetpack-ai-breve__header-container { - display: flex; - width: 100%; - justify-content: space-between; - gap: 32px; - height: 40px; - - .jetpack-ai-breve__title, - .jetpack-ai-breve__action { - padding: 8px 12px; - } - - .jetpack-ai-breve__title { - display: flex; - align-items: center; - justify-content: flex-start; - gap: 8px; - font-size: 14px; - font-weight: 500; - white-space: nowrap; - - .jetpack-ai-breve__color { - width: 10px; - height: 10px; - border-radius: 50%; - - @include features.features-colors( ( "background-color" ) ); - } - } - - .jetpack-ai-breve__action { - font-size: 13px; - display: flex; - align-items: center; - justify-content: flex-end; - gap: 4px; - - .jetpack-ai-breve__suggest.components-button { - padding-top: 0; - padding-bottom: 0; - padding-right: 0; - height: 24px; - - > svg, - path { - fill: #0277a8; - } - } - - .jetpack-ai-breve__loading { - height: 24px; - display: flex; - align-items: center; - - svg { - margin-top: 0; - } - } - } - } - - .jetpack-ai-breve__suggestions-container { - display: flex; - flex-direction: column; - border-top: 1px solid #dcdcde; - width: 100%; - - .jetpack-ai-breve__spelling-suggestion { - - + .jetpack-ai-breve__spelling-suggestion { - border-top: 1px solid #dcdcde; - } - - &.components-button.is-tertiary { - padding: 8px 12px; - } - } - - .components-button.is-tertiary { - color: #000; - white-space: break-spaces; - min-height: 36px; - height: unset; - min-width: 320px; - text-align: unset; - padding-top: 16px; - padding-bottom: 16px; - line-height: 20px; - } - } - - .jetpack-ai-breve__helper { - padding: 4px 8px; - background-color: #f6f7f7; - white-space: nowrap; - color: #646970; - margin: 4px; - border-radius: 4px; - font-size: 12px; - display: flex; - justify-content: space-between; - align-items: center; - gap: 8px; - width: calc(100% - 8px); - - .jetpack-ai-breve__helper-buttons-wrapper { - display: flex; - gap: 16px; - } - - .jetpack-ai-breve__helper-inner { - display: flex; - gap: 8px; - } - - .components-button { - padding: 0; - color: #646970; - } - - .ai-assistant-feedback { - - &__selection { - - .components-button:not(:disabled):hover { - color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)); - } - } - - &__thumb-selected { - color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)); - } - } - } - } -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/index.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/index.ts deleted file mode 100644 index a7d2ace51948..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Internal dependencies - */ -import Controls from './controls'; -import { store } from './store'; // Register the store -/** - * Types - */ -import { BreveControls } from './types'; - -const Breve = Controls as BreveControls; - -export { Breve }; -export { default as Highlight } from './highlight'; -export { registerBreveHighlights } from './utils/register-format'; -export { store }; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/actions.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/actions.ts deleted file mode 100644 index 15843db9d129..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/actions.ts +++ /dev/null @@ -1,176 +0,0 @@ -/** - * External dependencies - */ -import { askQuestionSync } from '@automattic/jetpack-ai-client'; -import { select } from '@wordpress/data'; -import { BREVE_FEATURE_NAME } from '../constants'; -import { getRequestMessages } from '../utils/get-request-messages'; -/** - * Types - */ -import type { Anchor } from '../types'; - -// ACTIONS - -export function setHighlightHover( isHover: boolean ) { - return { - type: 'SET_HIGHLIGHT_HOVER', - isHover, - }; -} - -export function setPopoverHover( isHover: boolean ) { - return { - type: 'SET_POPOVER_HOVER', - isHover, - }; -} - -export function setPopoverAnchor( anchor: Anchor ) { - return { - type: 'SET_POPOVER_ANCHOR', - anchor, - }; -} - -export function toggleProofread( force?: boolean ) { - const current = select( 'jetpack/ai-breve' ).isProofreadEnabled(); - const enabled = force === undefined ? ! current : force; - - return { - type: 'SET_PROOFREAD_ENABLED', - enabled, - }; -} - -export function toggleFeature( feature: string, force?: boolean ) { - const current = select( 'jetpack/ai-breve' ).isFeatureEnabled( feature ); - const enabled = force === undefined ? ! current : force; - - return { - type: enabled ? 'ENABLE_FEATURE' : 'DISABLE_FEATURE', - feature, - }; -} - -export function setDictionaryLoading( feature: string, loading: boolean ) { - return { - type: 'SET_DICTIONARY_LOADING', - feature, - loading, - }; -} - -export function setBlockMd5( blockId: string, md5: string ) { - return { - type: 'SET_BLOCK_MD5', - blockId, - md5, - }; -} - -export function invalidateSuggestions( blockId: string ) { - return { - type: 'INVALIDATE_SUGGESTIONS', - blockId, - }; -} - -export function ignoreSuggestion( blockId: string, id: string ) { - return { - type: 'IGNORE_SUGGESTION', - blockId, - id, - }; -} - -export function invalidateSingleSuggestion( feature: string, blockId: string, id: string ) { - return { - type: 'INVALIDATE_SINGLE_SUGGESTION', - feature, - blockId, - id, - }; -} - -export function reloadDictionary() { - return { - type: 'RELOAD_DICTIONARY', - }; -} - -export function setSuggestions( { - anchor, - id, - feature, - target, - text, - blockId, - occurrence, -}: { - anchor: HTMLElement; - id: string; - feature: string; - target: string; - text: string; - blockId: string; - occurrence: string; -} ) { - return ( { dispatch } ) => { - anchor?.classList?.add( 'jetpack-ai-breve__is-loading' ); - - dispatch( { - type: 'SET_SUGGESTIONS_LOADING', - id, - feature, - blockId, - loading: true, - } ); - - askQuestionSync( - getRequestMessages( { - feature, - target, - text, - blockId, - occurrence, - } ), - { - feature: BREVE_FEATURE_NAME, - } - ) - .then( response => { - anchor?.classList?.remove( 'jetpack-ai-breve__is-loading' ); - - try { - const suggestions = JSON.parse( response ); - dispatch( { - type: 'SET_SUGGESTIONS', - id, - feature, - suggestions, - blockId, - } ); - } catch { - dispatch( { - type: 'SET_SUGGESTIONS_LOADING', - id, - feature, - blockId, - loading: false, - } ); - } - } ) - .catch( () => { - anchor?.classList?.remove( 'jetpack-ai-breve__is-loading' ); - - dispatch( { - type: 'SET_SUGGESTIONS_LOADING', - id, - feature, - blockId, - loading: false, - } ); - } ); - }; -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/index.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/index.ts deleted file mode 100644 index 7eb81be6ee3b..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * WordPress dependencies - */ -import { createReduxStore, register } from '@wordpress/data'; -/** - * Internal dependencies - */ -import * as actions from './actions'; -import reducer from './reducer'; -import * as selectors from './selectors'; - -const STORE_NAME = 'jetpack/ai-breve'; - -export const store = createReduxStore( STORE_NAME, { - reducer, - selectors, - actions, -} ); - -register( store ); diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/reducer.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/reducer.ts deleted file mode 100644 index 40f90e998ae8..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/reducer.ts +++ /dev/null @@ -1,245 +0,0 @@ -/** - * WordPress dependencies - */ -import { combineReducers } from '@wordpress/data'; -/** - * Internal dependencies - */ -import features from '../features'; -/** - * Types - */ -import type { Anchor, BreveState } from '../types'; - -const enabledFromLocalStorage = window.localStorage.getItem( 'jetpack-ai-breve-enabled' ); -const disabledFeaturesFromLocalStorage = window.localStorage.getItem( - 'jetpack-ai-breve-disabled-features' -); -const initialConfiguration = { - enabled: enabledFromLocalStorage === 'true', - disabled: - disabledFeaturesFromLocalStorage !== null - ? JSON.parse( disabledFeaturesFromLocalStorage ) - : features - .filter( feature => ! feature.config.defaultEnabled ) - .map( feature => feature.config.name ), -}; - -export function configuration( - state: BreveState[ 'configuration' ] = initialConfiguration, - action: { type: string; enabled?: boolean; feature?: string; loading?: boolean } -) { - switch ( action.type ) { - case 'SET_PROOFREAD_ENABLED': { - const enabled = action?.enabled !== undefined ? action?.enabled : ! state?.enabled; - window.localStorage.setItem( 'jetpack-ai-breve-enabled', String( enabled ) ); - - return { - ...state, - enabled, - }; - } - - case 'ENABLE_FEATURE': { - const disabled = ( state.disabled ?? [] ).filter( feature => feature !== action.feature ); - window.localStorage.setItem( - 'jetpack-ai-breve-disabled-features', - JSON.stringify( disabled ) - ); - - return { - ...state, - disabled, - }; - } - - case 'DISABLE_FEATURE': { - const disabled = [ ...( state.disabled ?? [] ), action.feature ]; - window.localStorage.setItem( - 'jetpack-ai-breve-disabled-features', - JSON.stringify( disabled ) - ); - - return { - ...state, - disabled, - }; - } - - case 'SET_DICTIONARY_LOADING': { - const loading = action.loading - ? [ ...( state.loading ?? [] ), action.feature ] - : [ ...( state.loading ?? [] ) ].filter( feature => feature !== action.feature ); - - return { - ...state, - loading, - }; - } - - case 'RELOAD_DICTIONARY': { - return { - ...state, - reload: ! state.reload, - }; - } - } - - return state; -} - -const HIGHLIGHT_HOVERED_CLASS = 'jetpack-ai-breve__highlight-hovered'; - -export function popover( - state: BreveState[ 'popover' ] = {}, - action: { type: string; isHover?: boolean; anchor?: Anchor } -) { - const removeHoveredClass = () => { - state?.anchor?.target?.classList?.remove( HIGHLIGHT_HOVERED_CLASS ); - }; - - switch ( action.type ) { - case 'SET_HIGHLIGHT_HOVER': - if ( ! state?.isPopoverHover && ! action?.isHover ) { - removeHoveredClass(); - } - - return { - ...state, - isHighlightHover: action.isHover, - }; - - case 'SET_POPOVER_HOVER': - if ( ! state?.isHighlightHover && ! action?.isHover ) { - removeHoveredClass(); - } - - return { - ...state, - isPopoverHover: action.isHover, - }; - - case 'SET_POPOVER_ANCHOR': { - if ( ! action.anchor ) { - return state; - } - - const current = state?.anchor?.target; - const next = action?.anchor?.target; - - // Handle fast change of anchor - if ( current !== next ) { - removeHoveredClass(); - } - - next?.classList?.add( HIGHLIGHT_HOVERED_CLASS ); - - return { - ...state, - anchor: action.anchor, - }; - } - } - - return state; -} - -export function suggestions( - state = {}, - action: { - type: string; - id: string; - feature?: string; - blockId: string; - loading: boolean; - md5?: string; - suggestions?: { - revisedText: string; - suggestion: string; - }; - } -) { - const { id, feature, blockId } = action ?? {}; - const current = { ...state }; - const currentBlock = current?.[ blockId ] ?? {}; - const currentItem = current?.[ blockId ]?.[ feature ]?.[ id ] || {}; - - switch ( action.type ) { - case 'SET_SUGGESTIONS_LOADING': { - return { - ...current, - [ blockId ]: { - ...currentBlock, - [ feature ]: { - ...( currentBlock[ feature ] ?? {} ), - [ id ]: { - ...currentItem, - loading: action.loading, - }, - }, - }, - }; - } - - case 'SET_SUGGESTIONS': { - return { - ...current, - [ blockId ]: { - ...currentBlock, - [ feature ]: { - ...( currentBlock[ feature ] ?? {} ), - [ id ]: { - ...currentItem, - loading: false, - suggestions: action.suggestions, - }, - }, - }, - }; - } - - case 'SET_BLOCK_MD5': { - return { - ...current, - [ blockId ]: { - md5: action.md5, - ...currentBlock, - }, - }; - } - - case 'INVALIDATE_SUGGESTIONS': { - return { - ...current, - [ blockId ]: {}, - }; - } - - case 'INVALIDATE_SINGLE_SUGGESTION': { - return { - ...current, - [ blockId ]: { - ...currentBlock, - [ feature ]: { - ...( currentBlock[ feature ] ?? {} ), - [ id ]: {}, - }, - }, - }; - } - - case 'IGNORE_SUGGESTION': { - return { - ...current, - [ blockId ]: { - ...currentBlock, - ignored: [ ...( currentBlock.ignored ?? [] ), id ], - }, - }; - } - } - - return state; -} - -export default combineReducers( { popover, configuration, suggestions } ); diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/selectors.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/selectors.ts deleted file mode 100644 index 05f35ae1536e..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/store/selectors.ts +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Types - */ -import type { Anchor, BreveState } from '../types'; - -// Popover - -export function isHighlightHover( state: BreveState ) { - return state.popover?.isHighlightHover; -} - -export function isPopoverHover( state: BreveState ) { - return state.popover?.isPopoverHover; -} - -export function getPopoverAnchor( state: BreveState ): Anchor | null { - return state?.popover?.anchor ?? null; -} - -export function getPopoverLevel( state: BreveState ) { - return state.popover?.level; -} - -// Configuration - -export function isProofreadEnabled( state: BreveState ) { - return state.configuration?.enabled; -} - -export function isFeatureEnabled( state: BreveState, feature: string ) { - return ! state.configuration?.disabled?.includes( feature ); -} - -export function isFeatureDictionaryLoading( state: BreveState, feature: string ) { - return state.configuration?.loading?.includes( feature ); -} - -export function getDisabledFeatures( state: BreveState ) { - return state.configuration?.disabled; -} - -export function getReloadFlag( state: BreveState ) { - return state.configuration?.reload; -} - -// Suggestions - -export function getBlockMd5( state: BreveState, blockId: string ) { - return state.suggestions?.[ blockId ]?.md5 ?? ''; -} - -export function getSuggestionsLoading( - state: BreveState, - { feature, id, blockId }: { feature: string; id: string; blockId: string } -) { - return state.suggestions?.[ blockId ]?.[ feature ]?.[ id ]?.loading; -} - -export function getSuggestions( - state: BreveState, - { feature, id, blockId }: { feature: string; id: string; blockId: string } -) { - return state.suggestions?.[ blockId ]?.[ feature ]?.[ id ]?.suggestions; -} - -export function getIgnoredSuggestions( state: BreveState, { blockId }: { blockId: string } ) { - return state.suggestions?.[ blockId ]?.ignored; -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/types.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/types.ts deleted file mode 100644 index d9e99e932a14..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/types.ts +++ /dev/null @@ -1,146 +0,0 @@ -import type { JSX } from 'react'; - -export type BreveControls = () => JSX.Element; - -export type Anchor = { - target: HTMLElement; - virtual: { - getBoundingClientRect: () => DOMRect; - contextElement?: HTMLElement; - }; -}; - -export type BreveState = { - popover?: { - isHighlightHover?: boolean; - isPopoverHover?: boolean; - anchor?: Anchor; - level?: number; - }; - configuration?: { - enabled?: boolean; - disabled?: Array< string >; - loading?: Array< string >; - reload?: boolean; - }; - suggestions?: { - [ key: string ]: { - [ key: string ]: { - [ key: string ]: { - loading: boolean; - suggestions: { - html: string; - suggestion: string; - }; - }; - }; - }; - }; -}; - -export type BreveSelect = { - isHighlightHover: () => boolean; - isPopoverHover: () => boolean; - getPopoverAnchor: () => Anchor | null; - getPopoverLevel: () => number; - isProofreadEnabled: () => boolean; - isFeatureEnabled: ( feature: string ) => boolean; - isFeatureDictionaryLoading: ( feature: string ) => boolean; - getDisabledFeatures: () => Array< string >; - getBlockMd5: ( blockId: string ) => string; - getSuggestionsLoading: ( { - feature, - id, - blockId, - }: { - feature: string; - id: string; - blockId: string; - } ) => boolean; - getSuggestions: ( { - feature, - id, - blockId, - }: { - feature: string; - id: string; - blockId: string; - } ) => { - html: string; - suggestion: string; - }; - getIgnoredSuggestions: ( { blockId }: { blockId: string } ) => Array< string >; - getReloadFlag: () => boolean; -}; - -export type BreveDispatch = { - setHighlightHover: ( isHover: boolean ) => void; - setPopoverHover: ( isHover: boolean ) => void; - setPopoverAnchor: ( anchor: Anchor ) => void; - toggleProofread: ( force?: boolean ) => void; - toggleFeature: ( feature: string, force?: boolean ) => void; - setDictionaryLoading( feature: string, loading: boolean ): void; - invalidateSuggestions: ( blockId: string ) => void; - invalidateSingleSuggestion: ( feature: string, blockId: string, id: string ) => void; - reloadDictionary: () => void; - ignoreSuggestion: ( blockId: string, id: string ) => void; - setBlockMd5: ( blockId: string, md5: string ) => void; - setSuggestions: ( suggestions: { - anchor: Anchor[ 'target' ]; - id: string; - feature: string; - target: string; - text: string; - blockId: string; - occurrence: string; - } ) => void; -}; - -export type PlansSelect = { - getAiAssistantFeature: () => { - featuresControl: { [ key: string ]: FeatureControl }; - currentTier?: { - value?: number; - }; - }; -}; - -export type BreveFeatureConfig = { - name: string; - title: string; - tagName: string; - className: string; - defaultEnabled: boolean; -}; - -export type BreveFeature = { - config: BreveFeatureConfig; - highlight: ( text: string ) => Array< HighlightedText >; - dictionary?: { [ key: string ]: string }; - description: string; -}; - -export type HighlightedText = { - text: string; - suggestion?: string; - startIndex: number; - endIndex: number; -}; - -export type SpellChecker = { - correct: ( word: string ) => boolean; - suggest: ( word: string ) => Array< string >; - add: ( word: string ) => void; - personal: ( dic: string ) => void; -}; - -export type SpellingDictionaryContext = { - affix: string; - dictionary: string; -}; - -export type FeatureControl = { - enabled: boolean; - 'min-jetpack-version': string; - [ key: string ]: FeatureControl | boolean | string; -}; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/escape-regexp.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/escape-regexp.ts deleted file mode 100644 index 733295ea3a8e..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/escape-regexp.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const escapeRegExp = ( string: string ) => { - return string.replace( /[.*+?^${}()|[\]\\/]/g, '\\$&' ); -}; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/flesch-kincaid-utils.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/flesch-kincaid-utils.ts deleted file mode 100644 index d08cc101493c..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/flesch-kincaid-utils.ts +++ /dev/null @@ -1,45 +0,0 @@ -const countWords = ( text: string ) => { - return text.split( /\s+/ ).filter( word => word.length > 0 ).length; -}; - -const countSentences = ( text: string ) => { - return text.split( /[.!?]+/ ).filter( sentence => sentence.length > 0 ).length; -}; - -const countSyllables = ( word: string ) => { - if ( word.length <= 3 ) { - return 1; - } - - word = word - .toLowerCase() - .replace( /(?:[^laeiouy]es|ed|[^laeiouy]e)$/, '' ) - .replace( /^y/, '' ); - - const syllables = word.match( /[aeiouy]{1,2}/g ); - - return syllables ? syllables.length : 1; -}; - -const countTotalSyllables = ( text: string ) => { - return text.split( /\s+/ ).reduce( ( total, word ) => total + countSyllables( word ), 0 ); -}; - -const fleschKincaidGrade = ( words: number, sentences: number, syllables: number ) => { - if ( words === 0 || sentences === 0 ) { - return null; - } - - return 0.39 * ( words / sentences ) + 11.8 * ( syllables / words ) - 15.59; -}; - -const calculateFleschKincaid = ( text: string ) => { - const words = countWords( text ); - const sentences = countSentences( text ); - const syllables = countTotalSyllables( text ); - const gradeLevel = fleschKincaidGrade( words, sentences, syllables ); - - return gradeLevel; -}; - -export default calculateFleschKincaid; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-availability.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-availability.ts deleted file mode 100644 index ea1c9a6b58c6..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-availability.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * External dependencies - */ -import { wordpressPlansStore } from '@automattic/jetpack-shared-extension-utils/store/wordpress-com'; -import { select } from '@wordpress/data'; -import { store as editPostStore } from '@wordpress/edit-post'; -/** - * Internal dependencies - */ -import { getFeatureAvailability } from '../../../../../blocks/ai-assistant/lib/utils/get-feature-availability'; -/** - * Types - */ -import type { FeatureControl, PlansSelect } from '../types'; - -function getAiAssistantFeature() { - const { getAiAssistantFeature: getFeature } = select( - wordpressPlansStore - ) as unknown as PlansSelect; - - return getFeature(); -} - -export function getBreveAvailability() { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { currentTier, featuresControl } = getAiAssistantFeature(); - - // Disabled remotely. - if ( featuresControl?.[ 'write-brief' ]?.enabled === false ) { - return false; - } - - // Free plan users have access to Breve while it's in beta. - // const isFreePlan = currentTier?.value === 0; - // TODO: Review this logic when Breve is out of beta. - // if ( isFreePlan ) { - // return false; - // } - - const hiddenBlocks = select( editPostStore ).getHiddenBlockTypes?.() ?? []; - - // Not enabled if the AI Assistant block is hidden. - if ( hiddenBlocks.includes( 'jetpack/ai-assistant' ) ) { - return false; - } - - // Not enabled if the feature flag is intentionally disabled. - return getFeatureAvailability( 'ai-proofread-breve' ); -} - -export function canWriteBriefBeEnabled() { - const { featuresControl } = getAiAssistantFeature(); - - return featuresControl?.[ 'write-brief' ]?.enabled !== false; -} - -export function canWriteBriefFeatureBeEnabled( feature: string ) { - const { featuresControl } = getAiAssistantFeature(); - - return ( featuresControl?.[ 'write-brief' ]?.[ feature ] as FeatureControl )?.enabled !== false; -} - -export default getBreveAvailability; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-feature-data.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-feature-data.ts deleted file mode 100644 index 300cc1e0ddaa..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-feature-data.ts +++ /dev/null @@ -1,173 +0,0 @@ -/** - * External dependencies - */ -import { dispatch } from '@wordpress/data'; -import debugFactory from 'debug'; -/** - * Types - */ -import { BreveDispatch, SpellingDictionaryContext } from '../types'; - -const debug = debugFactory( 'jetpack-ai-breve:fetch-feature-data' ); - -type GetFeatureDataParams = { - feature: string; - language: string; - lastRequested?: string; -}; - -const briefData: { - // feature - [ key: string ]: { - // language - [ key: string ]: { - loading: boolean; - failed: boolean; - verified?: boolean; - data?: Array< string > | SpellingDictionaryContext; - }; - }; -} = {}; - -// Clear the local storage for the spelling context's old key. TODO: remove this after a few releases -localStorage.removeItem( 'jetpack-ai-breve-spelling-context-en' ); - -async function fetchFromServer( { - feature, - language, - lastRequested, -}: GetFeatureDataParams ): Promise< { - requestTime: string; - data: Array< string > | SpellingDictionaryContext | null; -} > { - // Randomize the server to balance the load - const counter = Math.floor( Math.random() * 3 ); - const url = `https://s${ counter }.wp.com/wp-content/lib/jetpack-ai/breve-dictionaries/${ feature }/${ language }.json`; - - // If we have a lastRequested date, first send a HEAD request to check if the data has been modified - // The If-Modified-Since header causes a CORS preflight request error, so we need to check manually - if ( lastRequested ) { - const headData = await fetch( url, { method: 'HEAD' } ); - const lastModified = headData.headers.get( 'last-modified' ); - - if ( ! lastModified ) { - throw new Error( 'Failed to fetch metadata' ); - } - - if ( new Date( lastRequested ) >= new Date( lastModified ) ) { - // If the data has not been modified, return null - return null; - } - } - - const requestTime = new Date().toUTCString(); - const data = await fetch( url ); - - if ( data.status === 404 ) { - throw new Error( 'The requested data does not exist' ); - } else if ( data.status !== 200 ) { - throw new Error( 'Failed to fetch data' ); - } - - return { - requestTime, - data: await data.json(), - }; -} - -async function fetchFeatureData( { feature, language, lastRequested }: GetFeatureDataParams ) { - debug( 'Fetching feature data for type: %s. language: %s', feature, language ); - - const { setDictionaryLoading } = dispatch( 'jetpack/ai-breve' ) as BreveDispatch; - - briefData[ feature ][ language ].loading = true; - - setDictionaryLoading( feature, true ); - - try { - const fetchedData = await fetchFromServer( { feature, language, lastRequested } ); - briefData[ feature ][ language ].verified = true; - - if ( ! fetchedData ) { - debug( 'Data not modified', feature, language ); - return; - } - - const { requestTime, data } = fetchedData; - - debug( 'Loaded data from server', feature, language ); - - // Cache the data in memory - briefData[ feature ][ language ].data = data; - - // Cache the data in local storage - localStorage.setItem( - `jetpack-ai-breve-data-${ feature }-${ language }`, - JSON.stringify( { requestTime, data } ) - ); - } catch ( error ) { - debug( 'Failed to fetch feature data context', error ); - briefData[ feature ][ language ].failed = true; - } finally { - briefData[ feature ][ language ].loading = false; - setDictionaryLoading( feature, false ); - } -} - -export default function getFeatureData( { feature, language }: GetFeatureDataParams ) { - // Initialize the feature data in memory, if it's not already defined - briefData[ feature ] = briefData[ feature ] || {}; - briefData[ feature ][ language ] = briefData[ feature ][ language ] || { - loading: false, - failed: false, - verified: false, - }; - - const { loading, failed, data, verified } = briefData[ feature ]?.[ language ] ?? { - loading: false, - failed: false, - }; - - // First check if the data is already loaded - if ( data ) { - return data; - } - - if ( loading ) { - return null; - } - - // Check if the feature data is already defined in local storage - const storedData = localStorage.getItem( `jetpack-ai-breve-data-${ feature }-${ language }` ); - let lastRequested: string; - - if ( storedData ) { - try { - const { requestTime, data: parsedData } = JSON.parse( storedData ); - - // If the data is verified or if requesting failed once, return the data we have. TODO: handle retries - if ( verified || failed ) { - debug( 'Loaded data from local storage', feature, language ); - - // Cache the data in memory - briefData[ feature ][ language ].data = parsedData ?? null; - return parsedData; - } - - // Set the last requested time to check if the data has been modified - lastRequested = requestTime; - } catch ( error ) { - debug( 'Failed to parse data from local storage', feature, language, error ); - // If we failed to parse the data, remove it from local storage, as it's likely corrupted - localStorage.removeItem( `jetpack-ai-breve-data-${ feature }-${ language }` ); - } - } - - // If the request failed once, don't try again. TODO: handle retries - if ( ! failed ) { - fetchFeatureData( { feature, language, lastRequested } ); - } - - // Return null if the data is not loaded yet, as the function is synchronous and will be called again - return null; -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-node-text-index.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-node-text-index.ts deleted file mode 100644 index ec0e9bc9e19a..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-node-text-index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Get the starting text index of a node's content within its parent's text content. - * Used to determine the position of a highlight within a sentence. - */ -export const getNodeTextIndex = ( parent: HTMLElement, node: HTMLElement ) => { - const nodes = Array.from( parent.childNodes ); - const nodePosition = nodes.indexOf( node ); - - const nodesBefore = nodes.slice( 0, nodePosition ); - const container = document.createElement( 'div' ); - - nodesBefore.forEach( n => container.appendChild( n.cloneNode( true ) ) ); - - return container.innerText.length; -}; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-non-link-ancestor.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-non-link-ancestor.ts deleted file mode 100644 index f1829e54c89c..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-non-link-ancestor.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Helper function to get the first non-link ancestor of an element. - * Used to determine the sentence context for a given word inside a link. - */ -export const getNonLinkAncestor = ( element: HTMLElement ) => { - let parent: HTMLElement | null = element?.parentElement ?? null; - - while ( parent && parent.tagName === 'A' ) { - parent = parent.parentElement; - } - - return parent; -}; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-post-text.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-post-text.ts deleted file mode 100644 index 3eea562b9929..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-post-text.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * External dependencies - */ -import * as Blocks from '@wordpress/blocks'; -/* - * Types - */ -import type { Block } from '@automattic/jetpack-ai-client'; - -const { getBlockContent } = Blocks as unknown as { - getBlockContent: ( block: Block ) => string; -}; - -export function getHtmlText( html: string ): string { - const doc = document.implementation.createHTMLDocument( '' ); - doc.body.innerHTML = html; - - // Prevent table cells from merging into one long word - doc.body.querySelectorAll( 'td, th' ).forEach( node => { - node.innerHTML = ` ${ node.innerHTML }`; - } ); - - // innerText returns rendered text, excluding hidden content - return doc.body.innerText; -} - -export function getPostText( blocks: Array< Block > ): string { - const html = blocks.map( block => getBlockContent( block ) ).join( '' ); - - return getHtmlText( html ); -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-request-messages.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-request-messages.ts deleted file mode 100644 index 1d1d7bc57c36..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-request-messages.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Internal dependencies - */ -import { getBlockContent } from '@wordpress/blocks'; -import { select } from '@wordpress/data'; -import features from '../features/index.ts'; - -// Map of types to the corresponding AI Assistant request type. -const requestTypeMap = { - 'complex-words': 'breve-complex-word', - 'unconfident-words': 'breve-unconfident-word', - 'long-sentences': 'breve-long-sentence', -}; - -export const getRequestMessages = ( { feature, target, text, blockId, occurrence } ) => { - const block = select( 'core/block-editor' ).getBlock( blockId ); - const html = getBlockContent( block ); - const dictionary = features?.find?.( ftr => ftr.config.name === feature )?.dictionary || {}; - const replacement = dictionary[ target.toLowerCase() ] || null; - - return [ - { - role: 'jetpack-ai' as const, - context: { - type: requestTypeMap[ feature ], - target, - text, - html, - replacement, - occurrence, - }, - }, - ]; -}; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-target-text.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-target-text.ts deleted file mode 100644 index 5beffd038b4c..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/get-target-text.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Internal dependencies - */ -import { getNodeTextIndex } from './get-node-text-index'; -import { getNonLinkAncestor } from './get-non-link-ancestor'; - -export default function getTargetText( anchor: HTMLElement ) { - const target = anchor?.innerText; - const parent = getNonLinkAncestor( anchor as HTMLElement ); - // The text containing the target - const text = parent?.innerText as string; - // Get the index of the target in the parent - const startIndex = getNodeTextIndex( parent as HTMLElement, anchor as HTMLElement ); - // Get the occurrences of the target in the sentence - const targetRegex = new RegExp( target, 'gi' ); - const matches = Array.from( text.matchAll( targetRegex ) ).map( match => match.index ); - // Get the right occurrence of the target in the sentence - const occurrence = Math.max( 1, matches.indexOf( startIndex ) + 1 ); - - return { target, parent, text, occurrence }; -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/number-to-ordinal.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/number-to-ordinal.ts deleted file mode 100644 index c04e102fd048..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/number-to-ordinal.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Converts a number to an ordinal string. - * Used to inform the AI model of the position of the right word in a sentence. - */ -export const numberToOrdinal = ( number: number ) => { - const suffix = [ 'th', 'st', 'nd', 'rd' ]; - const lastTwoDigits = number % 100; - - return ( - number + ( suffix[ ( lastTwoDigits - 20 ) % 10 ] || suffix[ lastTwoDigits ] || suffix[ 0 ] ) - ); -}; diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/register-format.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/register-format.ts deleted file mode 100644 index 68aee51fc255..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/register-format.ts +++ /dev/null @@ -1,146 +0,0 @@ -/** - * External dependencies - */ -import { getBlockContent } from '@wordpress/blocks'; -import { dispatch, select } from '@wordpress/data'; -import { registerFormatType, removeFormat, RichTextValue } from '@wordpress/rich-text'; -import md5 from 'crypto-js/md5'; -/** - * Internal dependencies - */ -import features from '../features'; -import registerEvents from '../features/events'; -import highlight from '../highlight/highlight'; -import { store as breveStore } from '../store'; -import { - getBreveAvailability, - canWriteBriefBeEnabled, - canWriteBriefFeatureBeEnabled, -} from '../utils/get-availability'; -/** - * Types - */ -import type { BreveDispatch, BreveFeature, BreveSelect } from '../types'; -import type { Block } from '@automattic/jetpack-ai-client'; - -type RichTextFormatList = RichTextValue[ 'formats' ][ number ]; -type WPFormat = Parameters< typeof registerFormatType >[ 1 ]; - -type CoreBlockEditorSelect = { - getBlock: ( clientId: string ) => Block; -}; - -export function getFormatName( featureName: string ) { - return `jetpack/ai-proofread-${ featureName }`; -} - -export function registerBreveHighlight( feature: BreveFeature ) { - if ( ! feature ) { - return; - } - - const { highlight: featureHighlight, config } = feature; - const { name, ...configSettings } = config; - const formatName = getFormatName( name ); - - const settings = { - name: formatName, - interactive: false, - object: false, - - edit: () => {}, - ...configSettings, - - __experimentalGetPropsForEditableTreePreparation( _select, { blockClientId } ) { - const { - getIgnoredSuggestions, - isFeatureEnabled, - isProofreadEnabled, - isFeatureDictionaryLoading, - getReloadFlag, - } = select( breveStore ) as unknown as BreveSelect; - - const canBeEnabled = canWriteBriefBeEnabled(); - const canFeatureBeEnabled = canWriteBriefFeatureBeEnabled( config.name ); - - return { - isProofreadEnabled: canBeEnabled && isProofreadEnabled() && getBreveAvailability(), - isFeatureEnabled: canFeatureBeEnabled && isFeatureEnabled( config.name ), - ignored: getIgnoredSuggestions( { blockId: blockClientId } ), - isFeatureDictionaryLoading: isFeatureDictionaryLoading( config.name ), - reloadFlag: getReloadFlag(), // Used to force a reload of the highlights - }; - }, - - __experimentalCreatePrepareEditableTree( - { isProofreadEnabled, isFeatureEnabled, ignored, isFeatureDictionaryLoading }, - { blockClientId, richTextIdentifier } - ) { - return ( formats: Array< RichTextFormatList >, text: string ) => { - const { getBlock } = select( 'core/block-editor' ) as CoreBlockEditorSelect; - const { getBlockMd5 } = select( breveStore ) as unknown as BreveSelect; - const { invalidateSuggestions, setBlockMd5 } = dispatch( - 'jetpack/ai-breve' - ) as BreveDispatch; - - const record = { formats, text } as RichTextValue; - const type = formatName; - - // Ignored suggestions - let ignoredList = ignored; - - // Has to be defined here, as adding it to __experimentalGetPropsForEditableTreePreparation - // causes an issue with the block inserter. ref p1721746774569699-slack-C054LN8RNVA - const currentMd5 = getBlockMd5( blockClientId ); - - if ( text && isProofreadEnabled && isFeatureEnabled && ! isFeatureDictionaryLoading ) { - const block = getBlock( blockClientId ); - let blockContent = text ?? ''; - - // Only use block content for complex blocks like tables - if ( richTextIdentifier !== 'content' && !! block ) { - blockContent = getBlockContent( block ); - } - - const textMd5 = md5( blockContent ).toString(); - - if ( currentMd5 !== textMd5 ) { - ignoredList = []; - invalidateSuggestions( blockClientId ); - setBlockMd5( blockClientId, textMd5 ); - } - - const highlights = featureHighlight( text ); - - const applied = highlight( { - ignored: ignoredList, - content: record, - type, - indexes: highlights, - attributes: { - 'data-breve-type': config.name, - 'data-identifier': richTextIdentifier ?? 'none', - 'data-block': blockClientId, - }, - } ); - - setTimeout( () => { - registerEvents( blockClientId ); - }, 100 ); - - return applied.formats; - } - - return removeFormat( record, type, 0, record.text.length ).formats; - }; - }, - } as WPFormat; - - registerFormatType( formatName, settings ); -} - -export function registerBreveHighlights() { - features.forEach( feature => { - registerBreveHighlight( feature ); - } ); -} diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/replace-occurrence.ts b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/replace-occurrence.ts deleted file mode 100644 index 834a7e789405..000000000000 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/breve/utils/replace-occurrence.ts +++ /dev/null @@ -1,18 +0,0 @@ -export default function replaceOccurrence( { - text, - target, - occurrence, - replacement, -}: { - text: string; - target: string; - occurrence: number; - replacement: string; -} ) { - const targetRegex = new RegExp( target, 'gi' ); - const matches = Array.from( text.matchAll( targetRegex ) ).map( match => match.index ); - const startIndex = matches[ occurrence - 1 ]; - const endIndex = startIndex + target.length; - - return text.substring( 0, startIndex ) + replacement + text.substring( endIndex ); -} From 2a955c3074a67ac714b413e0ef218080101bde89 Mon Sep 17 00:00:00 2001 From: Sarosh Aga Date: Fri, 3 Apr 2026 11:53:04 +0530 Subject: [PATCH 2/6] Fix changelog type for Jetpack plugin Use "other" instead of "removed" which is not a valid type for the Jetpack plugin changelogger. Co-Authored-By: Claude Opus 4.6 (1M context) --- projects/plugins/jetpack/changelog/remove-breve-write-brief | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/plugins/jetpack/changelog/remove-breve-write-brief b/projects/plugins/jetpack/changelog/remove-breve-write-brief index e73230867abd..238db7ab49a0 100644 --- a/projects/plugins/jetpack/changelog/remove-breve-write-brief +++ b/projects/plugins/jetpack/changelog/remove-breve-write-brief @@ -1,5 +1,5 @@ Significance: minor -Type: removed +Type: other Comment: Remove the Write Brief (Breve) proofreading feature from the AI Assistant. AI Assistant: Remove the Write Brief (Breve) proofreading feature. From 0340c59ac28fd1b1cc4acb727715981474079bf7 Mon Sep 17 00:00:00 2001 From: Sarosh Aga Date: Fri, 3 Apr 2026 12:00:35 +0530 Subject: [PATCH 3/6] Remove breve mocks from sidebar test The breve mock removals were lost during the rebase. This removes the jest.mock calls for ../../breve and ../../breve/utils/get-availability that reference the now-deleted breve directory. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ai-assistant-plugin-sidebar/test/index.test.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/ai-assistant-plugin-sidebar/test/index.test.tsx b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/ai-assistant-plugin-sidebar/test/index.test.tsx index 5eb665946cc4..129b6a077dca 100644 --- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/ai-assistant-plugin-sidebar/test/index.test.tsx +++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/ai-assistant-plugin-sidebar/test/index.test.tsx @@ -150,17 +150,6 @@ jest.mock( '../../../../../shared/jetpack-plugin-sidebar', () => ( { ), } ) ); -jest.mock( '../../breve', () => ( { - Breve: () => null, - registerBreveHighlights: jest.fn(), - Highlight: () => null, -} ) ); - -jest.mock( '../../breve/utils/get-availability', () => ( { - getBreveAvailability: () => false, - canWriteBriefBeEnabled: () => false, -} ) ); - jest.mock( '../../feedback', () => ( { __esModule: true, default: () => null } ) ); jest.mock( '../../title-optimization', () => ( { __esModule: true, default: () => null } ) ); jest.mock( '../../usage-panel', () => ( { __esModule: true, default: () => null } ) ); From 07273f8a104aa8b5404321e62d4c56d10779e801 Mon Sep 17 00:00:00 2001 From: Sarosh Aga Date: Fri, 3 Apr 2026 12:13:56 +0530 Subject: [PATCH 4/6] Fix remaining breve references lost during rebase The earlier edits targeted the main repo path instead of the worktree, so they were lost during rebase. This re-applies: breve imports/rendering removal in sidebar component, .write-brief-card styles, PHP registration, extension index entry, product page video card and unused newBadge variable. Co-Authored-By: Claude Opus 4.6 (1M context) --- pnpm-lock.yaml | 24 ---------- .../jetpack-ai/product-page.jsx | 44 ------------------- .../blocks/ai-assistant/ai-assistant.php | 6 --- .../plugins/jetpack/extensions/index.json | 1 - .../ai-assistant-plugin-sidebar/index.tsx | 20 --------- .../ai-assistant-plugin-sidebar/style.scss | 9 ---- 6 files changed, 104 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 734ce5c750f1..ca307bbfe315 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5068,9 +5068,6 @@ importers: copy-webpack-plugin: specifier: 14.0.0 version: 14.0.0(webpack@5.105.2) - crypto-js: - specifier: 4.2.0 - version: 4.2.0 debounce: specifier: 2.2.0 version: 2.2.0 @@ -5113,9 +5110,6 @@ importers: markdown-it-footnote: specifier: 3.0.3 version: 3.0.3 - nspell: - specifier: 2.1.5 - version: 2.1.5 photon: specifier: 4.1.1 version: 4.1.1 @@ -11739,9 +11733,6 @@ packages: crypt@0.0.2: resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} - crypto-js@4.2.0: - resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} - csp_evaluator@1.1.5: resolution: {integrity: sha512-EL/iN9etCTzw/fBnp0/uj0f5BOOGvZut2mzsiiBZ/FdT6gFQCKRO/tmcKOxn5drWZ2Ndm/xBb1SI4zwWbGtmIw==} @@ -13488,10 +13479,6 @@ packages: is-buffer@1.1.6: resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - is-buffer@2.0.5: - resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} - engines: {node: '>=4'} - is-bun-module@2.0.0: resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} @@ -14756,9 +14743,6 @@ packages: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - nspell@2.1.5: - resolution: {integrity: sha512-PSStyugKMiD9mHmqI/CR5xXrSIGejUXPlo88FBRq5Og1kO5QwQ5Ilu8D8O5I/SHpoS+mibpw6uKA8rd3vXd2Sg==} - nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} @@ -26598,8 +26582,6 @@ snapshots: crypt@0.0.2: {} - crypto-js@4.2.0: {} - csp_evaluator@1.1.5: {} css-declaration-sorter@7.3.1(postcss@8.5.6): @@ -28584,8 +28566,6 @@ snapshots: is-buffer@1.1.6: {} - is-buffer@2.0.5: {} - is-bun-module@2.0.0: dependencies: semver: 7.7.3 @@ -30246,10 +30226,6 @@ snapshots: dependencies: path-key: 4.0.0 - nspell@2.1.5: - dependencies: - is-buffer: 2.0.5 - nth-check@2.1.1: dependencies: boolbase: 1.0.0 diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/product-page.jsx b/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/product-page.jsx index 364741c15f02..32b14abe0074 100644 --- a/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/product-page.jsx +++ b/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/product-page.jsx @@ -58,8 +58,6 @@ export default function () { const videoTitleForms = __( 'Build forms using prompts', 'jetpack-my-jetpack' ); const videoTitleContentFeedback = __( 'Get feedback on posts', 'jetpack-my-jetpack' ); - const videoTitleBreve = __( 'Make your writing easy to read', 'jetpack-my-jetpack' ); - debug( aiAssistantFeature ); const { requestsCount: allTimeRequests = 0, @@ -88,8 +86,6 @@ export default function () { 'jetpack-ai-product-page-content-feedback-link' ); - const videoLinkBreve = getRedirectUrl( 'jetpack-ai-product-page-breve' ); - // isRegistered works as a flag to know if the page can link to a post creation or not const ctaURL = isRegistered ? 'post-new.php?use_ai_block=1&_wpnonce=' + window?.jetpackAi?.nonce @@ -203,12 +199,6 @@ export default function () { setShowNotice( showRenewalNotice || showUpgradeNotice ); }, [ showRenewalNotice, showUpgradeNotice ] ); - const newBadge = ( - - { __( 'New', 'jetpack-my-jetpack' ) }{ ' ' } - - ); - return ( @@ -353,40 +343,6 @@ export default function () { { __( 'Discover all the Jetpack features powered by AI', 'jetpack-my-jetpack' ) }

-
-
- - -
-
-
- { videoTitleBreve } - { newBadge } -
-
- { __( - 'Simplify your writing with AI suggestions to fix long sentences and complex words and sound more confident. As you type, check your Reading grade score to make sure it suits your audience.', - 'jetpack-my-jetpack' - ) } -
- -
-
-