Hi there, I'm fantasticit! 👋
可接付费咨询,付费开发,有意微信联系,微信同名。
Languages and Tools:
云策文档是一款开源知识管理工具。通过独立的知识库空间,结构化地组织在线协作文档,实现知识的积累与沉淀,促进知识的复用与流通。
Home Page: https://think.codingit.cn
License: MIT License
可接付费咨询,付费开发,有意微信联系,微信同名。
Languages and Tools:
大神,这个部署必须使用docker部署吗?有离线安装包解压的部署吗?有具体部署步骤吗?
目前公式无法编辑显示,是否考虑新增公式编辑器?
既然是MIT协议,为什么商用之前还要联系授权呢?
您好,我看咱们现在都是单文档分享
可以支持目录或整个知识库分享吗
这样的话,就更便捷了
GOAL: 本地源代码运行(生产环境)
After pnpm install
done
$ pnpm run build
> think@ build D:\project\think\think
> pnpm build:dep && pnpm build:server && pnpm build:client
> think@ build:dep D:\project\think\think
> pnpm build:constants && pnpm build:domains && pnpm build:config
> think@ build:constants D:\project\think\think
> pnpm run --dir packages/constants build
> @think/[email protected] build D:\project\think\think\packages\constants
> tsc src/*.ts --outDir lib --skipLibCheck --declaration --lib ES6
error TS6053: File 'src/*.ts' not found.
The file is in the program because:
Root file specified for compilation
ELIFECYCLE Command failed with exit code 2.
ELIFECYCLE Command failed with exit code 1.
ELIFECYCLE Command failed with exit code 1.
ELIFECYCLE Command failed with exit code 1.
try pnpm run dev
successfully but pnpm run build
failed, how can i build it
1、在插入表格的时候,表格一直不显示,貌似无法正确的插入表格;
2、在两段文本中间,插入代码块时,插入点后面的文本会被放入代码块中;
很不错的一个知识库啊,非常的需要这种开源又好用的知识库,和语雀很像,支持大佬继续开发优化;
配置里面是有oss/cos的配置可以填写,请问是怎样生效的,在默认的情况下,现在看到的是会存在本地上。
如果没有超级管理员 #63 ,这个功能改如何开启配置呢
最近正在做富文本的选型,感觉这里的比较好用,比直接用 tiptap 会省很多事情,能不能把富文本编辑器抽离成可以单独使用的 package 呢?
当前项目涉及的实体以及对应关系并不是很多,但是已经存在重复代码及众多接口的前后端认知协同问题,需要重新考虑代码设计。一种可能的设计:
提炼出数据模型的 interface、入参 dto、出参 dto 以及模型操作的抽象接口作为 @think/model
,前后端各自引入,各自实现对应的 service
。其中,前端页面可使用 mobx
与 mobx-react
对接接口实现服务,连接 react view 进行渲染。同时,借助 ioc 让代码整体只关注接口,而不关注具体的方法实现,完成解耦。
场景一:粘贴其他文档内容,应保留格式
场景二:复制粘贴纯文本
场景三:在文档编辑时,快速复制某一类型节点及其内容
npm ERR! code EAI_AGAIN
npm ERR! syscall getaddrinfo
npm ERR! errno EAI_AGAIN
npm ERR! request to https://registry.npm.taobao.org/@nestjs%2fcli failed, reason: getaddrinfo EAI_AGAIN registry.npm.taobao.org
npm ERR! A complete log of this run can be found in:
npm ERR! /root/.npm/_logs/2022-06-21T02_57_51_217Z-debug-0.log
The command '/bin/sh -c npm i -g pm2 @nestjs/cli pnpm' returned a non-zero code: 1
ERROR: Service 'thinkdoc' failed to build
另外:EIP设置ip应怎样设置
之前一直在用Outline处理个人整理的一些资料,今天pull了最新的代码,认真体验了下think wiki,大概使用了80%的功能,发现了一些问题,也有不小的惊喜,感觉假以时日,赶超Outline肯定没问题!
感谢作者!
希望能增加源码编辑模式,以及一键为目录增加编号功能
一开始就报错了:
[+] Running 0/2
⠇ mysql Pulling 2.8s
⠿ thinkdoc Error 2.7s
no matching manifest for linux/arm64/v8 in the manifest list entries
感谢作者的开源,这个项目体验很好!希望能够增加导出Word/PDF/Markdown文档格式的功能
项目部署Nginx反代的时候,是否能考虑加项目名,不要直接用端口
已提交PR #53 ,有需要的可自行拉取最新代码执行.
如果出现插件报错,替换 node_modules 下 y-cursor 的代码。
import * as Y from 'yjs'
import { Decoration, DecorationSet } from 'prosemirror-view' // eslint-disable-line
import { Plugin } from 'prosemirror-state' // eslint-disable-line
import { Awareness } from 'y-protocols/awareness' // eslint-disable-line
import { absolutePositionToRelativePosition, relativePositionToAbsolutePosition, setMeta } from '../lib.js'
import { yCursorPluginKey, ySyncPluginKey } from './keys.js'
import * as math from 'lib0/math'
/**
* Default generator for a cursor element
*
* @param {any} user user data
* @return HTMLElement
*/
export const defaultCursorBuilder = user => {
const cursor = document.createElement('span')
cursor.classList.add('ProseMirror-yjs-cursor')
cursor.setAttribute('style', `border-color: ${user.color}`)
const userDiv = document.createElement('div')
userDiv.setAttribute('style', `background-color: ${user.color}`)
userDiv.insertBefore(document.createTextNode(user.name), null)
cursor.insertBefore(userDiv, null)
return cursor
}
const rxValidColor = /^#[0-9a-fA-F]{6}$/
/**
* @param {any} state
* @param {Awareness} awareness
* @return {any} DecorationSet
*/
export const createDecorations = (state, awareness, createCursor) => {
const ystate = ySyncPluginKey.getState(state) || state['y-sync$'];
const y = ystate.doc
const decorations = []
if (ystate.snapshot != null || ystate.prevSnapshot != null || ystate.binding === null) {
// do not render cursors while snapshot is active
return DecorationSet.create(state.doc, [])
}
awareness.getStates().forEach((aw, clientId) => {
if (clientId === y.clientID) {
return
}
if (aw.cursor != null) {
const user = aw.user || {}
if (user.color == null) {
user.color = '#ffa500'
} else if (!rxValidColor.test(user.color)) {
// We only support 6-digit RGB colors in y-prosemirror
console.warn('A user uses an unsupported color format', user)
}
if (user.name == null) {
user.name = `User: ${clientId}`
}
let anchor = relativePositionToAbsolutePosition(y, ystate.type, Y.createRelativePositionFromJSON(aw.cursor.anchor), ystate.binding.mapping)
let head = relativePositionToAbsolutePosition(y, ystate.type, Y.createRelativePositionFromJSON(aw.cursor.head), ystate.binding.mapping)
if (anchor !== null && head !== null) {
const maxsize = math.max(state.doc.content.size - 1, 0)
anchor = math.min(anchor, maxsize)
head = math.min(head, maxsize)
decorations.push(Decoration.widget(head, () => createCursor(user), { key: clientId + '', side: 10 }))
const from = math.min(anchor, head)
const to = math.max(anchor, head)
decorations.push(Decoration.inline(from, to, { style: `background-color: ${user.color}70` }, { inclusiveEnd: true, inclusiveStart: false }))
}
}
})
return DecorationSet.create(state.doc, decorations)
}
/**
* A prosemirror plugin that listens to awareness information on Yjs.
* This requires that a `prosemirrorPlugin` is also bound to the prosemirror.
*
* @public
* @param {Awareness} awareness
* @param {object} [opts]
* @param {function(any):HTMLElement} [opts.cursorBuilder]
* @param {function(any):any} [opts.getSelection]
* @param {string} [opts.cursorStateField] By default all editor bindings use the awareness 'cursor' field to propagate cursor information.
* @return {any}
*/
export const yCursorPlugin = (awareness, { cursorBuilder = defaultCursorBuilder, getSelection = state => state.selection } = {}, cursorStateField = 'cursor') => new Plugin({
key: yCursorPluginKey,
state: {
init (_, state) {
return createDecorations(state, awareness, cursorBuilder)
},
apply (tr, prevState, oldState, newState) {
const ystate = ySyncPluginKey.getState(newState)
const yCursorState = tr.getMeta(yCursorPluginKey)
if ((ystate && ystate.isChangeOrigin) || (yCursorState && yCursorState.awarenessUpdated)) {
return createDecorations(newState, awareness, cursorBuilder)
}
return prevState.map(tr.mapping, tr.doc)
}
},
props: {
decorations: state => {
return yCursorPluginKey.getState(state)
}
},
view: view => {
const awarenessListener = () => {
// @ts-ignore
if (view.docView) {
setMeta(view, yCursorPluginKey, { awarenessUpdated: true })
}
}
const updateCursorInfo = () => {
const ystate = ySyncPluginKey.getState(view.state) || view.state['y-sync$'];
// @note We make implicit checks when checking for the cursor property
const current = awareness.getLocalState() || {}
if (view.hasFocus() && ystate.binding !== null) {
const selection = getSelection(view.state)
/**
* @type {Y.RelativePosition}
*/
const anchor = absolutePositionToRelativePosition(selection.anchor, ystate.type, ystate.binding.mapping)
/**
* @type {Y.RelativePosition}
*/
const head = absolutePositionToRelativePosition(selection.head, ystate.type, ystate.binding.mapping)
if (current.cursor == null || !Y.compareRelativePositions(Y.createRelativePositionFromJSON(current.cursor.anchor), anchor) || !Y.compareRelativePositions(Y.createRelativePositionFromJSON(current.cursor.head), head)) {
awareness.setLocalStateField(cursorStateField, {
anchor, head
})
}
} else if (current.cursor != null && relativePositionToAbsolutePosition(ystate.doc, ystate.type, Y.createRelativePositionFromJSON(current.cursor.anchor), ystate.binding.mapping) !== null) {
// delete cursor information if current cursor information is owned by this editor binding
awareness.setLocalStateField(cursorStateField, null)
}
}
awareness.on('change', awarenessListener)
view.dom.addEventListener('focusin', updateCursorInfo)
view.dom.addEventListener('focusout', updateCursorInfo)
return {
update: updateCursorInfo,
destroy: () => {
view.dom.removeEventListener('focusin', updateCursorInfo)
view.dom.removeEventListener('focusout', updateCursorInfo)
awareness.off('change', awarenessListener)
awareness.setLocalStateField(cursorStateField, null)
}
}
}
})
新建文档的时候,
在公开模板内选择任意一个模板,
点击模板上弹出的使用按钮会自动选择该模板,
再点击确定的时候提示我“您不是模板创建者,无法编辑”,
然而当我点击模板上右上角的编辑图标时,可以正常使用,进入的却是空白页面而没有文档的内容。
好家伙进入文档编辑界面的时候,我想点右上角的删除,然后又提示我您不是模板创建者,无法删除...
为了激活客户端的服务端渲染能力,需要:
set-cookie
,客户端就能在 node 端拿到 cookie 进行预请求swr
不太合适了,可以切换到 react-query
可行 demo:
方案:using-hydration
分支:cookie-ssr
流程图目前的实现是依赖 drawio 的 viewer.min.js 进行渲染,通过 https://embed.diagrams.net/
进行编辑,数据通信通过 postMessage
。不仅渲染卡顿,同时编辑器加载速度也慢,影响体验。
方案一:整合 mxgraph 的代码,工程量较大,且代码改造也有一定成本。
更好的方案?
如果这个功能实现,就可以从Obsidian 迁移出来了。
think 最初的定位是个人使用,优先支持 markdown,可分享,可协作。随着关注人数的增多,大家可能都有不同的需求,为了下一步规划,欢迎大家提出相关意见。
这样用户拉取一个 docker 镜像,然后通过 compose 文件可以方便快速的部署
启动之后,默认没有用户,创建的第一个用户和后面的用户都是普通用户。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.