Skip to content

Commit

Permalink
Merge pull request #46 from anc95/fix-shadowdom
Browse files Browse the repository at this point in the history
chore: export instructions
  • Loading branch information
anc95 authored Apr 12, 2023
2 parents 2255ec8 + 97fd4a5 commit 9405e9d
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 41 deletions.
22 changes: 22 additions & 0 deletions src/common/api/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,25 @@ export const remove = async (id: string) => {

await saveSetting(settings)
}

export const setTopPinned = async (id: string) => {
const settings = await getSetting()
let pinnedInsturction = null

settings.customInstructions = settings.customInstructions.filter((item) => {
if (item.id === id) {
pinnedInsturction = item
}

return item.id !== id
})

if (pinnedInsturction) {
settings.customInstructions = [
pinnedInsturction,
...settings.customInstructions,
]

await saveSetting(settings)
}
}
7 changes: 7 additions & 0 deletions src/common/file.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const download = (url: string, filename: string) => {
const a = document.createElement('a') as HTMLAnchorElement
a.href = url
a.download = filename

a.click()
}
2 changes: 1 addition & 1 deletion src/common/locale/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"Chinese": "Chinese",
"Append": "Append",
"Replace": "Replace",
"Prompt template": "Just Do whant I told you, the requirement is {{task}}, the content is '{{content}}'",
"Prompt template": "{{task}}:\n, {{content}}",
"Senior Writer": "Senior Writer",
"Send to writely": "Send to writely"
}
9 changes: 7 additions & 2 deletions src/common/locale/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"Chinese": "中文",
"Append": "添加",
"Replace": "替换内容",
"Prompt template": "按照我说的做, 要求是 {{task}}, 内容为 '{{content}}'",
"Prompt template": "{{task}}:\n, {{content}}",
"Senior Writer": "写作高手",
"Send to writely": "发送给 Writely",
"Change tone": "改变语调",
Expand Down Expand Up @@ -64,5 +64,10 @@
"Test": "测试",
"Test connection": "测试连接",
"Send message": "发送消息",
"Settings": "设置"
"Settings": "设置",
"Add new instruction": "添加新指令",
"Import": "导入",
"Export": "导出",
"Export instructions as JSON": "导出指令为JSON文件",
"Import instructions": "导入指令"
}
18 changes: 18 additions & 0 deletions src/components/icon/up.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { SVGProps } from 'react'

export function MaterialSymbolsArrowUpward(props: SVGProps<SVGSVGElement>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
{...props}
>
<path
fill="currentColor"
d="M11 20V7.825l-5.6 5.6L4 12l8-8l8 8l-1.4 1.425l-5.6-5.6V20h-2Z"
></path>
</svg>
)
}
30 changes: 15 additions & 15 deletions src/content/container/ask-writely/content/quick-prompt.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import { useMemo } from 'react';
import { PromptCenter } from '../prompts';
import { List, ListProps } from './list';
import { useMemo } from 'react'
import { PromptCenter } from '../prompts'
import { List, ListProps } from './list'

export const QuickPrompt: React.FC<{
filter: string;
onClick: (instruction: string) => void;
filter: string
onClick: (instruction: string) => void
}> = ({ filter, onClick }) => {
const promptCenter = useMemo(() => new PromptCenter(), []);
const items = promptCenter.useDropDownItems(filter);
const promptCenter = useMemo(() => new PromptCenter(), [])
const items = promptCenter.useDropDownItems(filter)

return (
<div>
{items.map((item, index) => (
<Card {...item} key={index} onClick={onClick} />
))}
</div>
);
};
)
}

const Card: React.FC<{
category: string;
menus: ListProps['items'];
onClick: (instruction: string) => void;
category: string
menus: ListProps['items']
onClick: (instruction: string) => void
}> = ({ category, menus, onClick }) => {
return (
<div
Expand All @@ -32,10 +32,10 @@ const Card: React.FC<{
<div className="text-gray-600 text-xs mb-1">{category}</div>
<List
items={menus}
max={4}
max={6}
onClick={(i) => onClick(i.instruction || (i.label as string))}
/>
</div>
</div>
);
};
)
}
29 changes: 15 additions & 14 deletions src/content/shadow-dom.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
const tag = 'writely-container';
const conatinerId = 'writely-container-id';
const tag = 'writely-container'
const conatinerId = 'writely-container-id'

// Create a class for the element
class WritelyContainer extends HTMLElement {
constructor() {
// Always call super first in constructor
super();
super()

// Create a shadow root
const shadow = this.attachShadow({ mode: 'open' });
const shadow = this.attachShadow({ mode: 'open' })

const container = document.createElement('div');
container.id = conatinerId;
container.setAttribute('style', 'font-size:16px;');
shadow.appendChild(container);
const container = document.createElement('div')
container.id = conatinerId
container.setAttribute('style', 'font-size:16px;')
shadow.appendChild(container)

/**
* Prevent bubble, cause the host website might listen them to make thing unexpected
* For example notion, it listens on keyup event to delete content
* https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
* https://developer.mozilla.org/en-US/docs/Web/API/InputEvent/inputType
*/
[
;[
'click',
'keydown',
'keypress',
Expand All @@ -30,13 +31,13 @@ class WritelyContainer extends HTMLElement {
'mouseup',
].forEach((eventName) => {
shadow.addEventListener(eventName, (e) => {
e.stopPropagation();
});
});
e.stopPropagation()
})
})
}
}

// Define the new element
customElements.define('writely-container', WritelyContainer);
customElements.define('writely-container', WritelyContainer)

export { tag, conatinerId };
export { tag, conatinerId }
2 changes: 1 addition & 1 deletion src/options/setting-form/instructions/actions/add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const Add: React.FC = () => {
const { setIsOpen } = useModalState()

return (
<Popover title="Add new instruction">
<Popover content={i18next.t('Add new instruction')}>
<Button onClick={() => setIsOpen(true)}>{i18next.t('Add')}</Button>
</Popover>
)
Expand Down
28 changes: 28 additions & 0 deletions src/options/setting-form/instructions/actions/export.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { download } from '@/common/file'
import { getSetting } from '@/common/store/settings'
import { Button, message, Popover } from 'antd'
import i18next from 'i18next'
import { useCallback } from 'react'

export const Export: React.FC = () => {
const handleExport = useCallback(async () => {
const settings = await getSetting()
const instructions = settings.customInstructions

if (!instructions || !instructions?.length) {
message.error(i18next.t('No data'))
return
}

const blob = new Blob([JSON.stringify(instructions)])
const url = URL.createObjectURL(blob)

download(url, 'writely-instructions.json')
}, [])

return (
<Popover content={i18next.t('Export instructions as JSON')}>
<Button onClick={handleExport}>{i18next.t('Export')}</Button>
</Popover>
)
}
22 changes: 22 additions & 0 deletions src/options/setting-form/instructions/actions/import.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Button, Popover, Upload } from 'antd'
import i18next from 'i18next'
import { useModalState } from '../modal-state'

export const Import: React.FC = () => {
const { setIsOpen } = useModalState()

return (
<Popover content={i18next.t('Import instructions')}>
<Upload
disabled
accept=".json"
showUploadList={false}
onChange={async ({ file }) => {
console.log(await file.originFileObj.text())
}}
>
<Button onClick={() => setIsOpen(true)}>{i18next.t('Import')}</Button>
</Upload>
</Popover>
)
}
4 changes: 4 additions & 0 deletions src/options/setting-form/instructions/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Instruction } from '@/options/types'
import { Add } from './actions/add'
import { Export } from './actions/export'
import { Import } from './actions/import'
import { InstructionModal } from './instruction-modal'
import { List } from './list'
import { ModalStateProvider } from './modal-state'
Expand All @@ -12,6 +14,8 @@ export const Instructions: React.FC<{ value?: Instruction[] }> = ({
<div>
<div className="flex gap-2 mb-2">
<Add />
<Export />
<Import />
</div>
<List value={value} />
<InstructionModal />
Expand Down
22 changes: 20 additions & 2 deletions src/options/setting-form/instructions/list.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { remove } from '@/common/api/instructions'
import { remove, setTopPinned } from '@/common/api/instructions'
import { useSettings } from '@/common/store/settings'
import { IconBtn } from '@/components/icon-btn'
import { IcBaselineDeleteOutline } from '@/components/icon/delete'
import { MaterialSymbolsEditOutline } from '@/components/icon/edit'
import { MaterialSymbolsArrowUpward } from '@/components/icon/up'
import { Instruction } from '@/options/types'
import { Popconfirm, Table, TableProps, Tooltip, Typography } from 'antd'
import {
Popconfirm,
Popover,
Table,
TableProps,
Tooltip,
Typography,
} from 'antd'
import i18next from 'i18next'
import { useModalState } from './modal-state'

Expand Down Expand Up @@ -77,6 +85,16 @@ const useColumns = () => {
>
<MaterialSymbolsEditOutline />
</IconBtn>
<Popover content={i18next.t('Top pinned')} trigger="hover">
<IconBtn
onClick={async () => {
await setTopPinned(record.id)
await refresh()
}}
>
<MaterialSymbolsArrowUpward />
</IconBtn>
</Popover>
</div>
)
},
Expand Down
11 changes: 7 additions & 4 deletions src/options/setting-form/open-api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const OPENAISettings: React.FC = () => {
</Select> */}
<Radio.Group className="flex flex-wrap gap-4">
{models.map((m) => (
<Radio className="" value={m.id}>
<Radio key={m.id} className="" value={m.id}>
<ModelCard {...m} />
</Radio>
))}
Expand Down Expand Up @@ -118,17 +118,20 @@ const ConnectionTest: React.FC = () => {
setResult('')

try {
queryOpenAIEdit(message, 'test', (text, err) => {
await queryOpenAIEdit(message, 'test', (text, err, end) => {
setResult(text)
setLoading(false)

if (err) {
setLoading(false)
setResult(err.message)
}

if (end) {
setLoading(false)
}
})
} catch (e) {
setResult(e.toString())
} finally {
setLoading(false)
}
}, [queryOpenAIEdit])
Expand Down
6 changes: 4 additions & 2 deletions src/options/setting-form/system.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ export const SystemSetting: React.FC = () => {
<Card title={i18next.t('System')} hoverable>
<Form.Item label={i18next.t('Language')} name="lang">
<Radio.Group>
{langs.map((lang) => (
<Radio.Button value={lang.value}>{lang.label}</Radio.Button>
{langs.map((lang, index) => (
<Radio.Button key={index} value={lang.value}>
{lang.label}
</Radio.Button>
))}
</Radio.Group>
</Form.Item>
Expand Down

0 comments on commit 9405e9d

Please sign in to comment.