mirror of
https://github.com/linsa-io/linsa.git
synced 2026-01-12 12:20:23 +01:00
fix: detail topic (#117)
* feat: keyboard nav * fix: link update * feat: reusable learning state * chore: use new learning state * feat: add to my profile * . * . * feat: on enter open the link * fix: lint * fix: use eslint v8 instead of v9 * fix: add to my profile * chore: update personal link schema * chore: update personal page schema * fix: update detail wrapper * fix: update page section * removing option for learning status * removing option for learning status for topic * feat: add createdAt and updatedAt for personal Page * chore: update page section component * chore: remove chevron from sub menu * fix: sidebar * chore: add focus and disable toast * feat: la editor add execption for no command class * fix: la editor style and fix page detail * fix: title * fix: topic learning state * chore: add showSearch for learning state * fix: bunch stuff * chore: link list and item handle learning state * chore: set expand to false * feat: personal link for topic detail * chore: hook use topic data * chore: go to list * fix: link and topic * feat(utils): new keyboard utils * feat(store): add linkOpenPopoverForIdAtom for link * chore: using memo for use topic data * fix: remove duplicate component * chore: performance for topic detail lint item * refactor: remove LinkOptions component * chore: improve performance for list * feat: added LinkRoute copmonent * chore: link manage * feat: bottom bar * fix: link * fix: page wrapper * fix: import thing * chore: added a displayname * refactor: page detail * refactor: page detail * fix: add topic to personal link form link * fix: only show page count if more than zero * fix: sidebar topic section --------- Co-authored-by: Nikita <github@nikiv.dev> Co-authored-by: marshennikovaolga <marshennikova@gmail.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import { icons } from "lucide-react"
|
||||
export type LearningStateValue = "wantToLearn" | "learning" | "learned"
|
||||
export type LearningState = {
|
||||
label: string
|
||||
value: string
|
||||
value: LearningStateValue
|
||||
icon: keyof typeof icons
|
||||
className: string
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ export class UserRoot extends CoMap {
|
||||
personalLinks = co.ref(PersonalLinkLists)
|
||||
personalPages = co.ref(PersonalPageLists)
|
||||
|
||||
// not implemented yet
|
||||
topicsWantToLearn = co.ref(ListOfTopics)
|
||||
topicsLearning = co.ref(ListOfTopics)
|
||||
topicsLearned = co.ref(ListOfTopics)
|
||||
@@ -53,7 +52,6 @@ export class LaAccount extends Account {
|
||||
personalLinks: PersonalLinkLists.create([], { owner: this }),
|
||||
personalPages: PersonalPageLists.create([], { owner: this }),
|
||||
|
||||
// not implemented yet
|
||||
topicsWantToLearn: ListOfTopics.create([], { owner: this }),
|
||||
topicsLearning: ListOfTopics.create([], { owner: this }),
|
||||
topicsLearned: ListOfTopics.create([], { owner: this })
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { co, CoList, CoMap } from "jazz-tools"
|
||||
|
||||
// TODO: this should be GlobalLink but it's not because lookup of 100k elements is slow
|
||||
export class Link extends CoMap {
|
||||
title = co.string
|
||||
url = co.string
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { co, CoList, CoMap, Encoders, ID } from "jazz-tools"
|
||||
import { Topic } from "./master/topic"
|
||||
import { Link, Topic } from "./master/topic"
|
||||
|
||||
class BaseModel extends CoMap {
|
||||
createdAt = co.encoded(Encoders.Date)
|
||||
@@ -9,6 +9,7 @@ class BaseModel extends CoMap {
|
||||
export class PersonalLink extends BaseModel {
|
||||
url = co.string
|
||||
icon = co.optional.string // is an icon URL
|
||||
link = co.optional.ref(Link)
|
||||
title = co.string
|
||||
slug = co.string
|
||||
description = co.optional.string
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { co, CoList, CoMap } from "jazz-tools"
|
||||
import { co, CoList, CoMap, Encoders } from "jazz-tools"
|
||||
import { Topic } from "./master/topic"
|
||||
|
||||
/*
|
||||
@@ -8,10 +8,13 @@ import { Topic } from "./master/topic"
|
||||
* - if public, certain members (can do read/write access accordingly), personal (end to end encrypted, only accessed by user)
|
||||
*/
|
||||
export class PersonalPage extends CoMap {
|
||||
title = co.string
|
||||
slug = co.string
|
||||
title = co.optional.string
|
||||
slug = co.optional.string // is used only when `public: true` for sharing, `@user/page-slug`
|
||||
public = co.boolean
|
||||
content = co.optional.json()
|
||||
topic = co.optional.ref(Topic)
|
||||
createdAt = co.encoded(Encoders.Date)
|
||||
updatedAt = co.encoded(Encoders.Date)
|
||||
// backlinks = co.optional.ref() // other PersonalPages linking to this page TODO: add, think through how to do it well, efficiently
|
||||
}
|
||||
|
||||
|
||||
@@ -11,3 +11,4 @@ export const randomId = () => {
|
||||
|
||||
export * from "./urls"
|
||||
export * from "./slug"
|
||||
export * from "./keyboard"
|
||||
|
||||
88
web/lib/utils/keyboard.ts
Normal file
88
web/lib/utils/keyboard.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
let isMac: boolean | undefined
|
||||
|
||||
interface Navigator {
|
||||
userAgentData?: {
|
||||
brands: { brand: string; version: string }[]
|
||||
mobile: boolean
|
||||
platform: string
|
||||
getHighEntropyValues: (hints: string[]) => Promise<{
|
||||
platform: string
|
||||
platformVersion: string
|
||||
uaFullVersion: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
function getPlatform(): string {
|
||||
const nav = navigator as Navigator
|
||||
|
||||
if (nav.userAgentData) {
|
||||
if (nav.userAgentData.platform) {
|
||||
return nav.userAgentData.platform
|
||||
}
|
||||
|
||||
nav.userAgentData.getHighEntropyValues(["platform"]).then(highEntropyValues => {
|
||||
if (highEntropyValues.platform) {
|
||||
return highEntropyValues.platform
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof navigator.platform === "string") {
|
||||
return navigator.platform
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
export function isMacOS() {
|
||||
if (isMac === undefined) {
|
||||
isMac = getPlatform().toLowerCase().includes("mac")
|
||||
}
|
||||
|
||||
return isMac
|
||||
}
|
||||
|
||||
interface ShortcutKeyResult {
|
||||
symbol: string
|
||||
readable: string
|
||||
}
|
||||
|
||||
export function getShortcutKey(key: string): ShortcutKeyResult {
|
||||
const lowercaseKey = key.toLowerCase()
|
||||
if (lowercaseKey === "mod") {
|
||||
return isMacOS() ? { symbol: "⌘", readable: "Command" } : { symbol: "Ctrl", readable: "Control" }
|
||||
} else if (lowercaseKey === "alt") {
|
||||
return isMacOS() ? { symbol: "⌥", readable: "Option" } : { symbol: "Alt", readable: "Alt" }
|
||||
} else if (lowercaseKey === "shift") {
|
||||
return { symbol: "⇧", readable: "Shift" }
|
||||
} else if (lowercaseKey === "control") {
|
||||
return { symbol: "⌃", readable: "Control" }
|
||||
} else if (lowercaseKey === "windows" && !isMacOS()) {
|
||||
return { symbol: "Win", readable: "Windows" }
|
||||
} else {
|
||||
return { symbol: key.toUpperCase(), readable: key }
|
||||
}
|
||||
}
|
||||
|
||||
export function getShortcutKeys(keys: string[]): ShortcutKeyResult[] {
|
||||
return keys.map(key => getShortcutKey(key))
|
||||
}
|
||||
|
||||
export function getSpecialShortcut(shortcutName: string): ShortcutKeyResult[] {
|
||||
if (shortcutName === "expandToolbar") {
|
||||
return isMacOS()
|
||||
? [getShortcutKey("control"), getShortcutKey("mod"), getShortcutKey("n")]
|
||||
: [getShortcutKey("mod"), getShortcutKey("windows"), getShortcutKey("n")]
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
export function formatShortcut(shortcutKeys: ShortcutKeyResult[]): string {
|
||||
return shortcutKeys.map(key => key.symbol).join("")
|
||||
}
|
||||
|
||||
export function formatReadableShortcut(shortcutKeys: ShortcutKeyResult[]): string {
|
||||
return shortcutKeys.map(key => key.readable).join(" + ")
|
||||
}
|
||||
Reference in New Issue
Block a user