Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	app/appearance/langs/en_US.json
#	app/appearance/langs/es_ES.json
#	app/appearance/langs/fr_FR.json
#	app/appearance/langs/zh_CHT.json
#	app/appearance/langs/zh_CN.json
This commit is contained in:
Vanessa 2023-02-24 15:26:30 +08:00
commit cdae86d50b
21 changed files with 144 additions and 58 deletions

View file

@ -1,4 +1,9 @@
{
"cardShowAnswer": "Show Answer",
"cardRatingAgain": "Again",
"cardRatingHard": "Hard",
"cardRatingGood": "Good",
"cardRatingEasy": "Easy",
"pdfIsLoading": "PDF is loading, please try again later",
"addToDeck": "Add to Deck...",
"quickMakeCard": "Quick make card",

View file

@ -1,5 +1,10 @@
{
"pdfIsLoading": "El PDF se está cargando, inténtalo de nuevo más tarde",
"cardShowAnswer": "Afficher la réponse",
"cardRatingAgain": "Otra vez",
"cardRatingHard": "Difícil",
"cardRatingGood": "Bueno",
"cardRatingEasy": "Fácil",
"addToDeck": "Agregar a la plataforma...",
"quickMakeCard": "Tarjeta de creación rápida",
"allAttrs": "Todos los nombres de atributos y valores de atributos",

View file

@ -1,4 +1,9 @@
{
"cardShowAnswer": "Afficher la réponse",
"cardRatingAgain": "Encore",
"cardRatingHard": "Difficile",
"cardRatingGood": "Bien",
"cardRatingEasy": "Facile",
"pdfIsLoading": "Le PDF est en cours de chargement, veuillez réessayer plus tard",
"addToDeck": "Ajouter au deck...",
"quickMakeCard": "Carte de création rapide",

View file

@ -1,5 +1,10 @@
{
"pdfIsLoading": "PDF 正在加載中,請稍後再試",
"cardShowAnswer": "顯示答案",
"cardRatingAgain": "重來",
"cardRatingHard": "困難",
"cardRatingGood": "一般",
"cardRatingEasy": "輕鬆",
"addToDeck": "添加到卡包...",
"quickMakeCard": "快速制卡",
"allAttrs": "所有屬性名和屬性值",

View file

@ -1,5 +1,10 @@
{
"pdfIsLoading": "PDF 正在加载中,请稍后再试",
"cardShowAnswer": "显示答案",
"cardRatingAgain": "重来",
"cardRatingHard": "困难",
"cardRatingGood": "一般",
"cardRatingEasy": "轻松",
"addToDeck": "添加到卡包...",
"quickMakeCard": "快速制卡",
"allAttrs": "所有属性名和属性值",

View file

@ -24,7 +24,7 @@
width: 90%;
& > div {
font-size: 46px;
font-size: 32px;
display: block;
line-height: 46px;
margin-bottom: 4px;

View file

@ -54,35 +54,35 @@ export const openCardByData = (cardsData: ICard[], html = "") => {
${window.siyuan.languages.noDueCard}
</div>
<div class="fn__flex card__action${blocks.length === 0 ? " fn__none" : ""}">
<button data-type="-1" class="b3-button fn__flex-1">Show (S)</button>
<button data-type="-1" class="b3-button fn__flex-1">${window.siyuan.languages.cardShowAnswer} (S)</button>
</div>
<div class="fn__flex card__action fn__none">
<div>
<span></span>
<button data-type="0" aria-label="1 / j" class="b3-button b3-button--error b3-tooltips__s b3-tooltips">
<div></div>
Again
${window.siyuan.languages.cardRatingAgain} (1)
</button>
</div>
<div>
<span></span>
<button data-type="1" aria-label="2 / k" class="b3-button b3-button--warning b3-tooltips__s b3-tooltips">
<div>😬</div>
Hard
${window.siyuan.languages.cardRatingHard} (2)
</button>
</div>
<div>
<span></span>
<button data-type="2" aria-label="3 / l" class="b3-button b3-button--info b3-tooltips__s b3-tooltips">
<div>😊</div>
Good
${window.siyuan.languages.cardRatingGood} (3)
</button>
</div>
<div>
<span></span>
<button data-type="3" aria-label="4 / ;" class="b3-button b3-button--success b3-tooltips__s b3-tooltips">
<div>🌈</div>
Easy
${window.siyuan.languages.cardRatingEasy} (4)
</button>
</div>
</div>

View file

@ -128,7 +128,7 @@ export const initFramework = () => {
closePanel();
});
initEditorName();
if (window.siyuan.config.newbie) {
if (window.siyuan.config.openHelp) {
mountHelp();
}
const transactionTipElement = document.getElementById("transactionTip");

View file

@ -413,7 +413,7 @@ declare interface IConfig {
api: {
token: string
}
newbie: boolean
openHelp: boolean
system: {
networkProxy: {
host: string

View file

@ -176,7 +176,7 @@ export const onGetConfig = (isStart: boolean) => {
resizeDrag();
}, 200);
});
if (window.siyuan.config.newbie) {
if (window.siyuan.config.openHelp) {
mountHelp();
}
addGA();

View file

@ -30,6 +30,7 @@ import (
"github.com/88250/lute"
"github.com/88250/lute/ast"
"github.com/88250/lute/parse"
"github.com/gabriel-vasile/mimetype"
"github.com/gin-gonic/gin"
"github.com/siyuan-note/filelock"
"github.com/siyuan-note/logging"
@ -80,7 +81,7 @@ func extensionCopy(c *gin.Context) {
continue
}
fName := path.Base(u.Path)
fName = util.FilterUploadFileName(fName)
f, err := file[0].Open()
if nil != err {
ret.Code = -1
@ -96,10 +97,19 @@ func extensionCopy(c *gin.Context) {
}
ext := path.Ext(fName)
fName = fName[0 : len(fName)-len(ext)]
originalExt := ext
if "" == ext || strings.Contains(ext, "!") {
// 改进浏览器剪藏扩展转换本地图片后缀 https://github.com/siyuan-note/siyuan/issues/7467
if mtype := mimetype.Detect(data); nil != mtype {
ext = mtype.Extension()
}
}
if "" == ext && bytes.HasPrefix(data, []byte("<svg ")) && bytes.HasSuffix(data, []byte("</svg>")) {
ext = ".svg"
}
fName = fName[0 : len(fName)-len(originalExt)]
fName = util.FilterUploadFileName(fName)
fName = fName + "-" + ast.NewNodeID() + ext
writePath := filepath.Join(assets, fName)
if err = filelock.WriteFile(writePath, data); nil != err {

View file

@ -35,7 +35,11 @@ func netImg2LocalAssets(c *gin.Context) {
}
id := arg["id"].(string)
err := model.NetImg2LocalAssets(id)
var url string
if urlArg := arg["url"]; nil != urlArg {
url = urlArg.(string)
}
err := model.NetImg2LocalAssets(id, url)
if nil != err {
ret.Code = -1
ret.Msg = err.Error()

View file

@ -47,7 +47,7 @@ require (
github.com/siyuan-note/filelock v0.0.0-20230223100551-200cbe1cf84e
github.com/siyuan-note/httpclient v0.0.0-20230223101139-409ed0b4c5ff
github.com/siyuan-note/logging v0.0.0-20230223101545-ec2cbf198ffb
github.com/siyuan-note/riff v0.0.0-20221228031102-17d458a1217b
github.com/siyuan-note/riff v0.0.0-20230224070227-4514ccc3e496
github.com/steambap/captcha v1.4.1
github.com/studio-b12/gowebdav v0.0.0-20230203202212-3282f94193f2
github.com/vmihailenco/msgpack/v5 v5.3.5

View file

@ -10,8 +10,6 @@ github.com/88250/gulu v1.2.3-0.20230223100136-26e5f16ac3c0 h1:hZn2F/kNKcxoK41Jhf
github.com/88250/gulu v1.2.3-0.20230223100136-26e5f16ac3c0/go.mod h1:pTWnjt+6qUqNnP9xltswsJxgCBVu3C7eW09u48LWX0k=
github.com/88250/lute v1.7.6-0.20230223100349-d4c62da413ce h1:PGos/Sz/SRVDPzToUgn/SBttEsAO5livLUWzoI+/bZ4=
github.com/88250/lute v1.7.6-0.20230223100349-d4c62da413ce/go.mod h1:+wUqx/1kdFDbWtxn9LYJlaCOAeol2pjSO6w+WJTVQsg=
github.com/88250/pdfcpu v0.3.14-0.20230223050947-68dec81c7661 h1:s8YOfk7TpajM8SBivP0ReIHmNfMQu20hWgEBc98D14w=
github.com/88250/pdfcpu v0.3.14-0.20230223050947-68dec81c7661/go.mod h1:S5YT38L/GCjVjmB4PB84PymA1qfopjEhfhTNQilLpv4=
github.com/88250/pdfcpu v0.3.14-0.20230224021324-e51076eb6390 h1:q2AR33VoQ87WYtvZ4pEvwj5gZkv22HK/yMlPWwF1oyc=
github.com/88250/pdfcpu v0.3.14-0.20230224021324-e51076eb6390/go.mod h1:S5YT38L/GCjVjmB4PB84PymA1qfopjEhfhTNQilLpv4=
github.com/88250/vitess-sqlparser v0.0.0-20210205111146-56a2ded2aba1 h1:48T899JQDwyyRu9yXHePYlPdHtpJfrJEUGBMH3SMBWY=
@ -288,8 +286,8 @@ github.com/siyuan-note/httpclient v0.0.0-20230223101139-409ed0b4c5ff h1:3G48J/tG
github.com/siyuan-note/httpclient v0.0.0-20230223101139-409ed0b4c5ff/go.mod h1:/fjYEiYPN2ZNR2zVTopobwzo3rOychV2qbsutxiV0jI=
github.com/siyuan-note/logging v0.0.0-20230223101545-ec2cbf198ffb h1:qzz7ZQw7/tHJd1IST+8UymXFF8RacokMLD7VZgyS+ww=
github.com/siyuan-note/logging v0.0.0-20230223101545-ec2cbf198ffb/go.mod h1:6mRFtAAvYPn3cDzqvyv+t8BVPGqpONDMMb5ywOhY1D4=
github.com/siyuan-note/riff v0.0.0-20221228031102-17d458a1217b h1:JDpKOdiyocNsgKFfrF3mB7UoBJz4qcHBUKBig78kVjc=
github.com/siyuan-note/riff v0.0.0-20221228031102-17d458a1217b/go.mod h1:WnNt0JPjfXp2fjAgbF9rS5W7JC2W0YVcaVmLXIeYF8A=
github.com/siyuan-note/riff v0.0.0-20230224070227-4514ccc3e496 h1:6u9vlE4EhRja4abccUPGNmG+aMBm/D+5lVomkoYuSmo=
github.com/siyuan-note/riff v0.0.0-20230224070227-4514ccc3e496/go.mod h1:XJtLlKCr8cZE+lzykM4edHHih92M9M50UNw/nDLYRN8=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.7 h1:I6tZjLXD2Q1kjvNbIzB1wvQBsXmKXiVrhpRE8ZjP5jY=

View file

@ -70,7 +70,7 @@ func DocImageAssets(rootID string) (ret []string, err error) {
return
}
func NetImg2LocalAssets(rootID string) (err error) {
func NetImg2LocalAssets(rootID, originalURL string) (err error) {
tree, err := loadTreeByBlockID(rootID)
if nil != err {
return
@ -138,6 +138,7 @@ func NetImg2LocalAssets(rootID string) (err error) {
}
util.PushUpdateMsg(msgId, fmt.Sprintf(Conf.Language(119), u), 15000)
request := httpclient.NewBrowserRequest()
request.SetHeader("Referer", originalURL) // 改进浏览器剪藏扩展转换本地图片成功率 https://github.com/siyuan-note/siyuan/issues/7464
resp, reqErr := request.Get(u)
if nil != reqErr {
logging.LogErrorf("download net img [%s] failed: %s", u, reqErr)

View file

@ -70,7 +70,7 @@ type AppConf struct {
Stat *conf.Stat `json:"stat"` // 统计
Api *conf.API `json:"api"` // API
Repo *conf.Repo `json:"repo"` // 数据仓库
Newbie bool `json:"newbie"` // 是否是安装后第一次启动
OpenHelp bool `json:"openHelp"` // 启动后是否需要打开用户指南
}
func InitConf() {
@ -211,7 +211,9 @@ func InitConf() {
}
if nil == Conf.System {
Conf.System = conf.NewSystem()
Conf.OpenHelp = true
} else {
Conf.OpenHelp = Conf.System.KernelVersion != util.Ver
Conf.System.KernelVersion = util.Ver
Conf.System.IsInsider = util.IsInsider
}
@ -237,7 +239,6 @@ func InitConf() {
}
Conf.System.OS = runtime.GOOS
Conf.System.OSPlatform, _ = util.GetOSPlatform()
Conf.Newbie = util.IsNewbie
if "" != Conf.UserData {
Conf.User = loadUserFromConf()

View file

@ -19,7 +19,6 @@ package model
import (
"errors"
"fmt"
"math"
"os"
"path"
"path/filepath"
@ -93,35 +92,10 @@ func (box *Box) docFromFileInfo(fileInfo *FileInfo, ial map[string]string) (ret
}
ret.Mtime = mTime.Unix()
ret.HMtime = HumanizeTime(mTime)
ret.HMtime = util.HumanizeTime(mTime, Conf.Lang)
return
}
func HumanizeTime(then time.Time) string {
labels := util.TimeLangs[Conf.Lang]
defaultMagnitudes := []humanize.RelTimeMagnitude{
{time.Second, labels["now"].(string), time.Second},
{2 * time.Second, labels["1s"].(string), 1},
{time.Minute, labels["xs"].(string), time.Second},
{2 * time.Minute, labels["1m"].(string), 1},
{time.Hour, labels["xm"].(string), time.Minute},
{2 * time.Hour, labels["1h"].(string), 1},
{humanize.Day, labels["xh"].(string), time.Hour},
{2 * humanize.Day, labels["1d"].(string), 1},
{humanize.Week, labels["xd"].(string), humanize.Day},
{2 * humanize.Week, labels["1w"].(string), 1},
{humanize.Month, labels["xw"].(string), humanize.Week},
{2 * humanize.Month, labels["1M"].(string), 1},
{humanize.Year, labels["xM"].(string), humanize.Month},
{18 * humanize.Month, labels["1y"].(string), 1},
{2 * humanize.Year, labels["2y"].(string), 1},
{humanize.LongTime, labels["xy"].(string), humanize.Year},
{math.MaxInt64, labels["max"].(string), 1},
}
return humanize.CustomRelTime(then, time.Now(), labels["albl"].(string), labels["blbl"].(string), defaultMagnitudes)
}
func (box *Box) docIAL(p string) (ret map[string]string) {
name := strings.ToLower(filepath.Base(p))
if !strings.HasSuffix(name, ".sy") {

View file

@ -29,7 +29,6 @@ import (
"github.com/88250/gulu"
"github.com/88250/lute/ast"
"github.com/88250/lute/parse"
"github.com/dustin/go-humanize"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/riff"
"github.com/siyuan-note/siyuan/kernel/cache"
@ -156,6 +155,9 @@ func GetFlashcards(deckID string, page int) (blocks []*Block, total, pageCount i
return
}
// reviewCardCache <cardID, card> 用于复习时缓存卡片,以便支持撤销。
var reviewCardCache = map[string]riff.Card{}
func ReviewFlashcard(deckID string, blockID string, rating riff.Rating) (err error) {
deckLock.Lock()
defer deckLock.Unlock()
@ -166,17 +168,39 @@ func ReviewFlashcard(deckID string, blockID string, rating riff.Rating) (err err
}
deck := Decks[deckID]
card := deck.GetCard(blockID)
if nil == card {
logging.LogErrorf("card not found [%s]", blockID)
return
}
if cachedCard := reviewCardCache[card.ID()]; nil != cachedCard {
// 命中缓存说明这张卡片已经复习过了,这次调用复习是撤销后再次复习
// 将缓存的卡片重新覆盖回卡包中,以恢复最开始复习前的状态
deck.SetCard(cachedCard)
} else {
// 首次复习该卡片,将卡片缓存以便后续支持撤销后再次复习
reviewCardCache[card.ID()] = card
}
deck.Review(blockID, rating)
err = deck.Save()
if nil != err {
logging.LogErrorf("save deck [%s] failed: %s", deckID, err)
return
}
dueCards := getDueFlashcards(deckID)
if 1 > len(dueCards) {
// 该卡包中没有待复习的卡片了,说明最后一张卡片已经复习完了,清空撤销缓存
reviewCardCache = map[string]riff.Card{}
}
return
}
type Flashcard struct {
DeckID string `json:"deckID"`
CardID string `json:"cardID"`
BlockID string `json:"blockID"`
NextDues map[riff.Rating]string `json:"nextDues"`
}
@ -207,11 +231,12 @@ func GetTreeDueFlashcards(rootID string) (ret []*Flashcard, err error) {
nextDues := map[riff.Rating]string{}
for rating, due := range card.NextDues() {
nextDues[rating] = strings.TrimSpace(humanize.RelTime(due, now, "", ""))
nextDues[rating] = strings.TrimSpace(util.HumanizeRelTime(due, now, Conf.Lang))
}
ret = append(ret, &Flashcard{
DeckID: builtinDeckID,
CardID: card.ID(),
BlockID: blockID,
NextDues: nextDues,
})
@ -270,10 +295,21 @@ func GetDueFlashcards(deckID string) (ret []*Flashcard, err error) {
}
if "" == deckID {
return getAllDueFlashcards()
ret = getAllDueFlashcards()
return
}
ret = getDueFlashcards(deckID)
return
}
func getDueFlashcards(deckID string) (ret []*Flashcard) {
deck := Decks[deckID]
if nil == deck {
logging.LogWarnf("deck not found [%s]", deckID)
return
}
cards := deck.Dues()
now := time.Now()
for _, card := range cards {
@ -285,11 +321,12 @@ func GetDueFlashcards(deckID string) (ret []*Flashcard, err error) {
nextDues := map[riff.Rating]string{}
for rating, due := range card.NextDues() {
nextDues[rating] = strings.TrimSpace(humanize.RelTime(due, now, "", ""))
nextDues[rating] = strings.TrimSpace(util.HumanizeRelTime(due, now, Conf.Lang))
}
ret = append(ret, &Flashcard{
DeckID: deckID,
CardID: card.ID(),
BlockID: blockID,
NextDues: nextDues,
})
@ -300,7 +337,7 @@ func GetDueFlashcards(deckID string) (ret []*Flashcard, err error) {
return
}
func getAllDueFlashcards() (ret []*Flashcard, err error) {
func getAllDueFlashcards() (ret []*Flashcard) {
blockIDs := map[string]bool{}
now := time.Now()
for _, deck := range Decks {
@ -317,11 +354,12 @@ func getAllDueFlashcards() (ret []*Flashcard, err error) {
nextDues := map[riff.Rating]string{}
for rating, due := range card.NextDues() {
nextDues[rating] = strings.TrimSpace(humanize.RelTime(due, now, "", ""))
nextDues[rating] = strings.TrimSpace(util.HumanizeRelTime(due, now, Conf.Lang))
}
ret = append(ret, &Flashcard{
DeckID: deck.ID,
CardID: card.ID(),
BlockID: blockID,
NextDues: nextDues,
})

View file

@ -162,8 +162,8 @@ func Mount(boxID string) (alreadyMount bool, err error) {
box.SaveConf(boxConf)
}
if Conf.Newbie {
Conf.Newbie = false
if Conf.OpenHelp {
Conf.OpenHelp = false
Conf.Save()
}

View file

@ -17,7 +17,11 @@
package util
import (
"math"
"strings"
"time"
"github.com/dustin/go-humanize"
)
func Millisecond2Time(t int64) time.Time {
@ -33,3 +37,37 @@ func CurrentTimeMillis() int64 {
func CurrentTimeSecondsStr() string {
return time.Now().Format("20060102150405")
}
func HumanizeRelTime(a time.Time, b time.Time, lang string) string {
_, magnitudes := humanizeTimeMagnitudes(lang)
return strings.TrimSpace(humanize.CustomRelTime(a, b, "", "", magnitudes))
}
func HumanizeTime(then time.Time, lang string) string {
labels, magnitudes := humanizeTimeMagnitudes(lang)
return strings.TrimSpace(humanize.CustomRelTime(then, time.Now(), labels["albl"].(string), labels["blbl"].(string), magnitudes))
}
func humanizeTimeMagnitudes(lang string) (labels map[string]interface{}, magnitudes []humanize.RelTimeMagnitude) {
labels = TimeLangs[lang]
magnitudes = []humanize.RelTimeMagnitude{
{time.Second, labels["now"].(string), time.Second},
{2 * time.Second, labels["1s"].(string), 1},
{time.Minute, labels["xs"].(string), time.Second},
{2 * time.Minute, labels["1m"].(string), 1},
{time.Hour, labels["xm"].(string), time.Minute},
{2 * time.Hour, labels["1h"].(string), 1},
{humanize.Day, labels["xh"].(string), time.Hour},
{2 * humanize.Day, labels["1d"].(string), 1},
{humanize.Week, labels["xd"].(string), humanize.Day},
{2 * humanize.Week, labels["1w"].(string), 1},
{humanize.Month, labels["xw"].(string), humanize.Week},
{2 * humanize.Month, labels["1M"].(string), 1},
{humanize.Year, labels["xM"].(string), humanize.Month},
{18 * humanize.Month, labels["1y"].(string), 1},
{2 * humanize.Year, labels["2y"].(string), 1},
{humanize.LongTime, labels["xy"].(string), humanize.Year},
{math.MaxInt64, labels["max"].(string), 1},
}
return
}

View file

@ -180,15 +180,12 @@ var (
SnippetsPath string // 数据目录下的 snippets/ 路径
UIProcessIDs = sync.Map{} // UI 进程 ID
IsNewbie bool // 是否是第一次安装
)
func initWorkspaceDir(workspaceArg string) {
userHomeConfDir := filepath.Join(HomeDir, ".config", "siyuan")
workspaceConf := filepath.Join(userHomeConfDir, "workspace.json")
if !gulu.File.IsExist(workspaceConf) {
IsNewbie = ContainerStd == Container // 只有桌面端需要设置新手标识,前端自动挂载帮助文档
if err := os.MkdirAll(userHomeConfDir, 0755); nil != err && !os.IsExist(err) {
log.Printf("create user home conf folder [%s] failed: %s", userHomeConfDir, err)
os.Exit(ExitCodeCreateConfDirErr)