mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-09 03:50:49 +00:00
Merge pull request #16156 from overleaf/jdt-writefull-notif
Writefull editor notification GitOrigin-RevId: 1a5077164682dbec67738af0684d364571802816
This commit is contained in:
parent
771f07d7ad
commit
a9d7f99446
14 changed files with 77 additions and 23 deletions
|
@ -851,6 +851,7 @@ module.exports = {
|
|||
sourceEditorComponents: [],
|
||||
sourceEditorCompletionSources: [],
|
||||
sourceEditorSymbolPalette: [],
|
||||
writefullEditorPromotion: [],
|
||||
langFeedbackLinkingWidgets: [],
|
||||
integrationLinkingWidgets: [],
|
||||
referenceLinkingWidgets: [],
|
||||
|
|
|
@ -1448,8 +1448,11 @@
|
|||
"work_offline": "",
|
||||
"work_with_non_overleaf_users": "",
|
||||
"writefull": "",
|
||||
"writefull_how_to": "",
|
||||
"writefull_learn_more": "",
|
||||
"writefull_prompt_body": "",
|
||||
"writefull_prompt_title": "",
|
||||
"writefull_settings_description": "",
|
||||
"writefull_settings_instructions": "",
|
||||
"x_changes_in": "",
|
||||
"x_changes_in_plural": "",
|
||||
"x_price_for_first_month": "",
|
||||
|
|
|
@ -12,6 +12,7 @@ type EnableWidgetProps = {
|
|||
title: string
|
||||
description: string
|
||||
helpPath: string
|
||||
helpTextOverride?: string
|
||||
hasFeature?: boolean
|
||||
isPremiumFeature?: boolean
|
||||
statusIndicator?: ReactNode
|
||||
|
@ -27,6 +28,7 @@ export function EnableWidget({
|
|||
title,
|
||||
description,
|
||||
helpPath,
|
||||
helpTextOverride,
|
||||
hasFeature,
|
||||
isPremiumFeature,
|
||||
statusIndicator,
|
||||
|
@ -37,6 +39,7 @@ export function EnableWidget({
|
|||
disabled,
|
||||
}: EnableWidgetProps) {
|
||||
const { t } = useTranslation()
|
||||
const helpText = helpTextOverride || t('learn_more')
|
||||
|
||||
return (
|
||||
<div className="settings-widget-container">
|
||||
|
@ -51,7 +54,7 @@ export function EnableWidget({
|
|||
<p className="small">
|
||||
{description}{' '}
|
||||
<a href={helpPath} target="_blank" rel="noreferrer">
|
||||
{t('learn_more')}
|
||||
{helpText}
|
||||
</a>
|
||||
</p>
|
||||
{children}
|
||||
|
|
|
@ -2,19 +2,12 @@ import { useCallback, useEffect, useState } from 'react'
|
|||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import * as eventTracking from '../../../infrastructure/event-tracking'
|
||||
import customLocalStorage from '../../../infrastructure/local-storage'
|
||||
import grammarlyExtensionPresent from '../../../shared/utils/grammarly'
|
||||
import useWaitForGrammarlyCheck from '@/shared/hooks/use-wait-for-grammarly-check'
|
||||
export default function GrammarlyAdvert() {
|
||||
const [show, setShow] = useState(false)
|
||||
|
||||
// grammarly can take some time to load, and wont tell us when they do... so we need to run the check after a bit of time
|
||||
const [grammarlyInstalled, setGrammarlyInstalled] = useState(false)
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(
|
||||
() => setGrammarlyInstalled(grammarlyExtensionPresent()),
|
||||
5000
|
||||
)
|
||||
return () => clearTimeout(timer)
|
||||
}, [])
|
||||
// grammarly can take some time to load, we should assume its installed and hide until we know for sure
|
||||
const grammarlyInstalled = useWaitForGrammarlyCheck({ initialState: false })
|
||||
|
||||
useEffect(() => {
|
||||
const hasDismissedGrammarlyAdvert = customLocalStorage.getItem(
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
import { lazy, memo, Suspense } from 'react'
|
||||
import { lazy, memo, Suspense, ElementType } from 'react'
|
||||
import { FullSizeLoadingSpinner } from '../../../shared/components/loading-spinner'
|
||||
import withErrorBoundary from '../../../infrastructure/error-boundary'
|
||||
import { ErrorBoundaryFallback } from '../../../shared/components/error-boundary-fallback'
|
||||
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
||||
|
||||
const writefullPromotion = importOverleafModules(
|
||||
'writefullEditorPromotion'
|
||||
) as {
|
||||
import: { default: ElementType }
|
||||
path: string
|
||||
}[]
|
||||
|
||||
const CodeMirrorEditor = lazy(
|
||||
() =>
|
||||
|
@ -11,6 +19,9 @@ const CodeMirrorEditor = lazy(
|
|||
function SourceEditor() {
|
||||
return (
|
||||
<Suspense fallback={<FullSizeLoadingSpinner delay={500} />}>
|
||||
{writefullPromotion.map(({ import: { default: Component }, path }) => (
|
||||
<Component key={path} />
|
||||
))}
|
||||
<CodeMirrorEditor />
|
||||
</Suspense>
|
||||
)
|
||||
|
|
|
@ -19,6 +19,7 @@ import { useSplitTestContext } from '../../../../../shared/context/split-test-co
|
|||
import { User } from '../../../../../../../types/user'
|
||||
import { useUserContext } from '../../../../../shared/context/user-context'
|
||||
import grammarlyExtensionPresent from '../../../../../shared/utils/grammarly'
|
||||
import { EditorTutorials } from '../../../../../../../types/tutorial'
|
||||
import { debugConsole } from '../../../../../utils/debugging'
|
||||
|
||||
const DELAY_BEFORE_SHOWING_PROMOTION = 1000
|
||||
|
@ -26,11 +27,6 @@ const NEW_USER_CUTOFF_TIME = new Date(2023, 8, 20).getTime()
|
|||
const NOW_TIME = new Date().getTime()
|
||||
const GRAMMARLY_CUTOFF_TIME = new Date(2023, 9, 10).getTime()
|
||||
|
||||
type EditorTutorials = {
|
||||
inactiveTutorials: [string]
|
||||
deactivateTutorial: (key: string) => void
|
||||
}
|
||||
|
||||
const editorContextPropTypes = {
|
||||
inactiveTutorials: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
deactivateTutorial: PropTypes.func.isRequired,
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} delay how long to wait before checking for grammarly in ms
|
||||
* @param {boolean} initialState the initial state we should set grammarlyInstalled to before checking after the delay
|
||||
* @returns {boolean} a stateful boolean which is initially false, then updates to reflect whether grammarly is installed after the delay to check
|
||||
*/
|
||||
export default function useWaitForGrammarlyCheck({
|
||||
delay = 3000,
|
||||
initialState = false,
|
||||
}) {
|
||||
const [grammarlyInstalled, setGrammarlyInstalled] = useState(() => {
|
||||
return initialState
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(
|
||||
() => setGrammarlyInstalled(grammarlyExtensionPresent()),
|
||||
delay
|
||||
)
|
||||
return () => clearTimeout(timer)
|
||||
}, [delay])
|
||||
return grammarlyInstalled
|
||||
}
|
||||
|
||||
function grammarlyExtensionPresent() {
|
||||
return !!document.querySelector('grammarly-desktop-integration')
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
function WritefullLogo({ width = '40', height = '40' }) {
|
||||
function WritefullLogo({ width = '40', height = '40', background = 'none' }) {
|
||||
return (
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox="0 0 40 40"
|
||||
fill="none"
|
||||
fill={background}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
style={{ verticalAlign: 'middle' }}
|
||||
|
|
|
@ -752,3 +752,9 @@ CodeMirror
|
|||
grammarly-extension[data-grammarly-shadow-root='true'] {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.writefull-notification {
|
||||
margin: 48px 64px;
|
||||
width: 80%;
|
||||
max-width: 560px;
|
||||
}
|
||||
|
|
|
@ -149,3 +149,4 @@
|
|||
@import 'modules/git-bridge-modal.less';
|
||||
@import 'modules/group-settings.less';
|
||||
@import 'modules/overleaf-integration.less';
|
||||
@import 'modules/writefull.less';
|
||||
|
|
3
services/web/frontend/stylesheets/modules/writefull.less
Normal file
3
services/web/frontend/stylesheets/modules/writefull.less
Normal file
|
@ -0,0 +1,3 @@
|
|||
.writefull-logo-bg {
|
||||
background-color: #fff;
|
||||
}
|
|
@ -2105,8 +2105,11 @@
|
|||
"work_with_word_users_blurb": "__appName__ is so easy to get started with that you’ll be able to invite your non-LaTeX colleagues to contribute directly to your LaTeX documents. They’ll be productive from day one and be able to pick up small amounts of LaTeX as they go.",
|
||||
"would_you_like_to_see_a_university_subscription": "Would you like to see a university-wide __appName__ subscription at your university?",
|
||||
"writefull": "Writefull",
|
||||
"writefull_how_to": "[COPY PLACEHOLDER] to use Writefull, select some text and press the shortcut key. a toolbar will appear with the results.",
|
||||
"writefull_settings_description": "Writefull is a new feature that helps you improve your writing by highlighting common errors and suggesting improvements.",
|
||||
"writefull_learn_more": "Learn more about Writefull for Overleaf",
|
||||
"writefull_prompt_body": "Turn on the new Writefull integration to get AI-powered language feedback specifically tailored to research writing.",
|
||||
"writefull_prompt_title": "AI writing assistance in Overleaf",
|
||||
"writefull_settings_description": "Get free AI-based language feedback specifically tailored for research writing with Writefull for Overleaf. Plus, if you upgrade to Writefull Premium you can use TeXGPT to generate LaTeX code—use OVERLEAF10 at the checkout to get 10% off.",
|
||||
"writefull_settings_instructions": "To use Writefull, log in from the Writefull toolbar in the Overleaf editor. And don’t forget, if you upgrade to Writefull Premium you can use TeXGPT to generate LaTeX code—use OVERLEAF10 at the checkout to get 10% off.",
|
||||
"x_changes_in": "__count__ change in",
|
||||
"x_changes_in_plural": "__count__ changes in",
|
||||
"x_collaborators_per_project": "__collaboratorsCount__ collaborators per project",
|
||||
|
|
5
services/web/types/tutorial.ts
Normal file
5
services/web/types/tutorial.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
// todo: maybe change this to just tutorials, and move it from editor context to user context?
|
||||
export type EditorTutorials = {
|
||||
inactiveTutorials: [string]
|
||||
deactivateTutorial: (key: string) => void
|
||||
}
|
|
@ -42,6 +42,6 @@ declare global {
|
|||
useRecaptchaNet?: boolean
|
||||
}
|
||||
expectingLinkedFileRefreshedSocketFor?: string | null
|
||||
writefull?: Map<string, any>
|
||||
writefull?: any
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue