WIP: feature cards, fir merging highlights offline sync

This commit is contained in:
Jackson Harper
2023-04-04 21:04:13 +08:00
parent 2b62bff958
commit 8e3aba2295
21 changed files with 594 additions and 42 deletions

View File

@ -0,0 +1,39 @@
//
// LibraryFeatureCardNavigationLink.swift
//
//
// Created by Jackson Harper on 4/4/23.
//
import Models
import Services
import SwiftUI
import Views
struct LibraryFeatureCardNavigationLink: View {
@EnvironmentObject var dataService: DataService
@EnvironmentObject var audioController: AudioController
let item: LinkedItem
@ObservedObject var viewModel: HomeFeedViewModel
var body: some View {
ZStack {
Button {
viewModel.selectedItem = item
viewModel.linkIsActive = true
} label: {
NavigationLink(destination: EmptyView()) {
EmptyView()
}
.opacity(0)
.buttonStyle(PlainButtonStyle())
.onAppear {
Task { await viewModel.itemAppeared(item: item, dataService: dataService) }
}
LibraryFeatureCard(item: item, viewer: dataService.currentViewer)
}
}
}
}

View File

@ -354,6 +354,52 @@ import Views
}
}
var featureCard: some View {
VStack(alignment: .leading, spacing: 20) {
Menu(content: {
Button(action: {
viewModel.featureFilter = .continueReading
}, label: {
Text("Continue Reading")
})
Button(action: {
viewModel.featureFilter = .recommended
}, label: {
Text("Recommended")
// Label("Recommended", systemImage: "x.circle")
})
Button(action: {
viewModel.featureFilter = .newsletters
}, label: {
Text("Newsletters")
// Label("Newsletters", systemImage: "x.circle")
})
}, label: {
HStack(alignment: .center) {
Text(viewModel.featureFilter.title.uppercased())
.font(Font.system(size: 14, weight: .medium))
Image(systemName: "chevron.down")
}
})
.padding(.top, 20)
.padding(.bottom, 0)
ScrollView(.horizontal, showsIndicators: false) {
LazyHStack(alignment: .top, spacing: 20) {
ForEach(viewModel.featureItems) { item in
LibraryFeatureCardNavigationLink(item: item, viewModel: viewModel)
}
}.padding(0)
}
.padding(.top, 0)
Text((LinkedItemFilter(rawValue: viewModel.appliedFilter)?.displayName ?? "Inbox").uppercased())
.font(Font.system(size: 14, weight: .medium))
.padding(.bottom, 5)
}
}
var body: some View {
ZStack {
NavigationLink(
@ -371,14 +417,20 @@ import Views
List {
filtersHeader
.listRowSeparator(.hidden, edges: .top)
.listRowInsets(.init(top: 0, leading: 10, bottom: 10, trailing: 10))
if viewModel.featureItems.count > 0 {
featureCard
.listRowInsets(.init(top: 0, leading: 10, bottom: 10, trailing: 10))
}
ForEach(viewModel.items) { item in
FeedCardNavigationLink(
item: item,
viewModel: viewModel
)
.listRowInsets(.init(top: 0, leading: 8, bottom: 8, trailing: 8))
.listRowSeparatorTint(Color.thBorderColor)
.listRowInsets(.init(top: 0, leading: 10, bottom: 10, trailing: 10))
.contextMenu {
menuItems(for: item)
}

View File

@ -33,6 +33,9 @@ import Views
@Published var showLabelsSheet = false
@Published var showCommunityModal = false
@Published var featureFilter = FeaturedItemFilter.continueReading
@Published var featureItems = [LinkedItem]()
var cursor: String?
// These are used to make sure we handle search result
@ -44,6 +47,21 @@ import Views
@AppStorage(UserDefaultKey.lastSelectedLinkedItemFilter.rawValue) var appliedFilter = LinkedItemFilter.inbox.rawValue
func setItems(_ items: [LinkedItem]) {
self.items = items
// now try to update the continue reading items:
featureItems = items.filter { item in
featureFilter.predicate.evaluate(with: item)
}
.sorted(by: { left, right in
if let lreadAt = left.readAt, let rreadAt = right.readAt {
return lreadAt > rreadAt
}
return false
})
}
func handleReaderItemNotification(objectID: NSManagedObjectID, dataService: DataService) {
// Pop the current selected item if needed
if selectedItem != nil, selectedItem?.objectID != objectID {
@ -166,9 +184,9 @@ import Views
// Don't use FRC for searching. Use server results directly.
if fetchedResultsController != nil {
fetchedResultsController = nil
items = []
setItems([])
}
items = isRefresh ? newItems : items + newItems
setItems(isRefresh ? newItems : items + newItems)
}
isLoading = false
@ -266,7 +284,7 @@ import Views
fetchedResultsController.delegate = self
try? fetchedResultsController.performFetch()
items = fetchedResultsController.fetchedObjects ?? []
setItems(fetchedResultsController.fetchedObjects ?? [])
}
func setLinkArchived(dataService: DataService, objectID: NSManagedObjectID, archived: Bool) {
@ -340,6 +358,6 @@ import Views
extension HomeFeedViewModel: NSFetchedResultsControllerDelegate {
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
items = controller.fetchedObjects as? [LinkedItem] ?? []
setItems(controller.fetchedObjects as? [LinkedItem] ?? [])
}
}

View File

@ -74,6 +74,10 @@ public extension LinkedItem {
readingProgress <= 0
}
var isPartiallyRead: Bool {
Int(readingProgress) > 0
}
var isRead: Bool {
readingProgress >= 0.98
}

View File

@ -89,3 +89,49 @@ public extension LinkedItemFilter {
}
}
}
public enum FeaturedItemFilter: String, CaseIterable {
case continueReading
case recommended
case newsletters
}
public extension FeaturedItemFilter {
var title: String {
switch self {
case .continueReading:
return "Continue Reading"
default:
return rawValue
}
}
var predicate: NSPredicate {
let undeletedPredicate = NSPredicate(
format: "%K != %i", #keyPath(LinkedItem.serverSyncStatus), Int64(ServerSyncStatus.needsDeletion.rawValue)
)
let notInArchivePredicate = NSPredicate(
format: "%K == %@", #keyPath(LinkedItem.isArchived), Int(truncating: false) as NSNumber
)
switch self {
case .continueReading:
let continueReadingPredicate = NSPredicate(
format: "readingProgress > 1 AND readAt != nil"
)
return NSCompoundPredicate(andPredicateWithSubpredicates: [continueReadingPredicate, undeletedPredicate, notInArchivePredicate])
case .newsletters:
// non-archived or deleted items with the Newsletter label
let newsletterLabelPredicate = NSPredicate(
format: "SUBQUERY(labels, $label, $label.name == \"Newsletter\").@count > 0"
)
return NSCompoundPredicate(andPredicateWithSubpredicates: [notInArchivePredicate, newsletterLabelPredicate])
case .recommended:
// non-archived or deleted items with the Newsletter label
let recommendedPredicate = NSPredicate(
format: "recommendations.@count > 0"
)
return NSCompoundPredicate(andPredicateWithSubpredicates: [notInArchivePredicate, recommendedPredicate])
}
}
}

View File

@ -40,7 +40,7 @@ extension DataService {
)
// Send update to server
syncHighlightCreation(highlight: internalHighlight, articleId: articleId)
syncHighlightMerge(highlight: internalHighlight, articleId: articleId, overlapHighlightIdList: overlapHighlightIdList)
return internalHighlight.encoded()
}

View File

@ -31,6 +31,7 @@ public extension Color {
static var themeTTSReadingText: Color { Color("_themeTTSReadingText", bundle: .module) }
static var themeDisabledBG: Color { Color("_themeDisabledBG", bundle: .module) }
static var themeSolidBackground: Color { Color("_themeSolidBackground", bundle: .module) }
static var thBorderColor: Color { Color("thBorderColor", bundle: .module) }
// Apple system UIColor equivalents
#if os(iOS)

View File

@ -2,7 +2,7 @@
"colors" : [
{
"color" : {
"color-space" : "srgb",
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0x18",

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xE1",
"green" : "0xE1",
"red" : "0xE1"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x4F",
"green" : "0x4F",
"red" : "0x4F"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -5,9 +5,9 @@
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0x89",
"green" : "0x89",
"red" : "0x89"
"blue" : "0x68",
"green" : "0x69",
"red" : "0x69"
}
},
"idiom" : "universal"

View File

@ -0,0 +1,120 @@
import Models
import SwiftUI
import Utils
public struct LibraryFeatureCard: View {
let viewer: Viewer?
let tapHandler: () -> Void
@ObservedObject var item: LinkedItem
public init(item: LinkedItem, viewer: Viewer?, tapHandler: @escaping () -> Void = {}) {
self.item = item
self.viewer = viewer
self.tapHandler = tapHandler
}
public var body: some View {
VStack(alignment: .leading, spacing: 5) {
imageBox
title
readInfo
Spacer()
}
.padding(0)
.frame(maxWidth: 150)
}
var isFullyRead: Bool {
item.readingProgress > 95
}
var isPartiallyRead: Bool {
Int(item.readingProgress) > 0
}
var readingSpeed: Int64 {
var result = UserDefaults.standard.integer(forKey: UserDefaultKey.userWordsPerMinute.rawValue)
if result <= 0 {
result = 235
}
return Int64(result)
}
var estimatedReadingTime: String {
if item.wordsCount > 0 {
let readLen = max(1, item.wordsCount / readingSpeed)
return "\(readLen) MIN READ • "
}
return ""
}
var readingProgress: String {
// If there is no wordsCount don't show progress because it will make no sense
if item.wordsCount > 0 {
return "\(String(format: "%d", Int(item.readingProgress)))%"
}
return ""
}
var readInfo: some View {
AnyView(HStack {
Text("\(estimatedReadingTime)")
.font(Font.system(size: 11, weight: .medium))
.foregroundColor(Color.themeMediumGray)
+
Text("\(readingProgress)")
.font(Font.system(size: 11, weight: .medium))
.foregroundColor(isPartiallyRead ? Color.appGreenSuccess : Color.themeMediumGray)
}
.frame(maxWidth: 150, alignment: .leading))
}
var imageBox: some View {
Group {
if let imageURL = item.imageURL {
AsyncImage(url: imageURL) { phase in
switch phase {
case .empty:
Color.systemBackground
.frame(width: 150, height: 90)
.cornerRadius(8)
case let .success(image):
image.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 150, height: 90)
.cornerRadius(8)
case .failure:
Image(systemName: "photo")
.frame(width: 150, height: 90)
.foregroundColor(Color(hex: "#6A6968"))
.background(Color(hex: "#EBEBEB"))
.cornerRadius(8)
@unknown default:
// Since the AsyncImagePhase enum isn't frozen,
// we need to add this currently unused fallback
// to handle any new cases that might be added
// in the future:
EmptyView()
}
}
} else {
Image(systemName: "photo")
.frame(width: 150, height: 90)
.foregroundColor(Color(hex: "#6A6968"))
.background(Color(hex: "#EBEBEB"))
.cornerRadius(8)
}
}
}
var title: some View {
Text(item.unwrappedTitle.trimmingCharacters(in: .whitespacesAndNewlines))
.multilineTextAlignment(.leading)
.font(Font.system(size: 13, weight: .semibold))
.lineSpacing(1.25)
.foregroundColor(.appGrayTextContrast)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(2)
.frame(maxWidth: .infinity, minHeight: 33, alignment: .topLeading)
}
}

View File

@ -16,10 +16,10 @@ public struct LibraryItemCard: View {
public var body: some View {
VStack {
HStack(alignment: .top, spacing: 0) {
readIndicator
articleInfo
imageBox
}
.padding(5)
.frame(maxWidth: .infinity, maxHeight: .infinity)
if item.hasLabels {
@ -40,7 +40,7 @@ public struct LibraryItemCard: View {
var readIndicator: some View {
HStack {
Circle()
.foregroundColor(item.readingProgress > 0 ? .clear : .indicatorBlue)
.foregroundColor( /* item.readingProgress > 0 ? .clear : */ .indicatorBlue)
.frame(width: 9, height: 9, alignment: .topLeading)
.padding(.top, 22)
.padding(.leading, 0)
@ -78,6 +78,7 @@ public struct LibraryItemCard: View {
if let highlights = item.highlights, highlights.count > 0 {
let fmted = LocalText.pluralizedText(key: "number_of_highlights", count: highlights.count)
if item.wordsCount > 0 {
print(" - highlightsText: ", "\(fmted)")
return "\(fmted)"
}
return fmted
@ -145,7 +146,7 @@ public struct LibraryItemCard: View {
}
}
}
}.opacity(isFullyRead ? 0.4 : 1.0)
}
}
var bylineStr: String {
@ -190,8 +191,9 @@ public struct LibraryItemCard: View {
Text(item.unwrappedTitle)
.font(Font.system(size: 18, weight: .semibold))
.lineSpacing(1.25)
.foregroundColor(isFullyRead ? Color.themeMediumGray : .appGrayTextContrast)
.foregroundColor(.appGrayTextContrast)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(2)
byLine
}
@ -213,7 +215,6 @@ public struct LibraryItemCard: View {
#endif
}
.padding(.top, 0)
.padding(.leading, 20)
#if os(macOS)
.onTapGesture {
tapHandler()

File diff suppressed because one or more lines are too long

View File

@ -52,10 +52,7 @@ const mutation = async (name, input) => {
const App = () => {
applyStoredTheme(false)
document.addEventListener('updateLabels', (event) => {
console.log('updating labels: ', event.labels)
setLabels(event.labels)
})
console.log('rerendering: ', window.omnivoreArticle)
return (
<>

View File

@ -25,6 +25,7 @@ import {
} from '../elements/ModalPrimitives'
import { CloseButton } from '../elements/CloseButton'
import { StyledText } from '../elements/StyledText'
import remarkGfm from 'remark-gfm'
const mdParser = new MarkdownIt()
@ -326,7 +327,10 @@ export function MarkdownNote(props: MarkdownNote): JSX.Element {
}}
onClick={() => props.setEditMode('edit')}
>
<ReactMarkdown children={props.text ?? props.placeHolder} />
<ReactMarkdown
children={props.text ?? props.placeHolder}
remarkPlugins={[remarkGfm]}
/>
</SpanBox>
</>
)}

View File

@ -11,8 +11,9 @@ import {
HStack,
} from '../elements/LayoutPrimitives'
import { styled } from '../tokens/stitches.config'
import { HighlightViewNote, MarkdownModal } from './HighlightNotes'
import { HighlightViewNote } from './HighlightNotes'
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
type HighlightViewProps = {
highlight: Highlight
@ -83,7 +84,10 @@ export function HighlightView(props: HighlightViewProps): JSX.Element {
},
}}
>
<ReactMarkdown children={props.highlight.quote ?? ''} />
<ReactMarkdown
children={props.highlight.quote ?? ''}
remarkPlugins={[remarkGfm]}
/>
</SpanBox>
</StyledQuote>
<Box css={{ display: 'block', pt: '5px' }}>

View File

@ -230,6 +230,12 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
const percent =
(selection.getRangeAt(0).getBoundingClientRect().y + window.scrollY) /
window.document.scrollingElement.scrollHeight
console.log(
'percent breakdown: ',
selection.getRangeAt(0).getBoundingClientRect().y,
window.scrollY,
window.document.scrollingElement.scrollHeight
)
return Math.min(Math.max(0, percent * 100), 100)
}
return undefined
@ -258,6 +264,7 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
const createHighlightCallback = useCallback(
async (successAction: HighlightModalAction, annotation?: string) => {
console.log('creating highlight from: ', selectionData)
if (!selectionData) {
return
}

View File

@ -51,16 +51,25 @@ export async function createHighlight(
return {}
}
console.log(
' input.selection.overlapHighlights: ',
input.selection.overlapHighlights
)
const shouldMerge = input.selection.overlapHighlights.length > 0
const { range, selection } = input.selection
console.log('original range: ', range.toString())
extendRangeToWordBoundaries(range)
// Create a temp container for copying the range HTML
const container = document.createElement('div')
container.appendChild(range.cloneContents())
console.log(' - html: ', container.innerHTML)
console.log(' - markdown: ', htmlToMarkdown(container.innerHTML))
const id = uuidv4()
const patch = generateDiffPatch(range)

View File

@ -9,9 +9,8 @@ import type { SelectionAttributes } from './highlightHelpers'
export function useSelection(
highlightLocations: HighlightLocation[]
): [SelectionAttributes | null, (x: SelectionAttributes | null) => void] {
const [touchStartPos, setTouchStartPos] = useState<
{ x: number; y: number } | undefined
>(undefined)
const [touchStartPos, setTouchStartPos] =
useState<{ x: number; y: number } | undefined>(undefined)
const [selectionAttributes, setSelectionAttributes] =
useState<SelectionAttributes | null>(null)
@ -62,6 +61,13 @@ export function useSelection(
let shouldCancelSelection = false
const overlapHighlights: HighlightLocation[] = []
console.log(
'checking highlight locations for ',
selectionStart,
selectionEnd
)
console.log(' highlight locations: ', highlightLocations)
highlightLocations
.sort((a, b) => {
if (a.start < b.start) {
@ -138,13 +144,16 @@ export function useSelection(
}, 100)
}
console.log('range rect: ', rangeRect, 'tapAttributes', tapAttributes)
return setSelectionAttributes({
selection,
wasDragEvent,
range: mergedRange ?? range,
focusPosition: {
x: rangeRect[isReverseSelected ? 'left' : 'right'],
y: rangeRect[isReverseSelected ? 'top' : 'bottom'],
// x: rangeRect[isReverseSelected ? 'left' : 'right'],
// y: rangeRect[isReverseSelected ? 'top' : 'bottom'],
x: tapAttributes.tapX,
y: tapAttributes.tapY,
isReverseSelected,
},
overlapHighlights: overlapHighlights.map(({ id }) => id),

View File

@ -60,6 +60,7 @@
"react-super-responsive-table": "^5.2.1",
"react-topbar-progress-indicator": "^4.1.1",
"react-twitter-widgets": "^1.10.0",
"remark-gfm": "^3.0.1",
"swr": "^1.0.1",
"uuid": "^8.3.2"
},
@ -99,4 +100,4 @@
"node": "14.18.0",
"yarn": "1.22.10"
}
}
}

226
yarn.lock
View File

@ -8532,11 +8532,6 @@
resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.0.1.tgz#2b1657096473e24b049bdedf3710f99645f3a17f"
integrity sha512-/LAvk1cMOJt0ghzMFrZEvByUhsiEfeeT2IF53Le+Ki3A538yEL9pRZ7a6MuCxdrYK+YNqNIDmrKU/r2nnw04zQ==
"@types/markdown-escape@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@types/markdown-escape/-/markdown-escape-1.1.0.tgz#8bd940d6701880eb7229467542c029bc05a7b22f"
integrity sha512-bJZh73L6fSt8MmTON/btR8hiKRipoIoPfLO41lxr6l65QXdG1rwUjR8Hu5xU7XYHBwKHiJZ+sTQ8L2TKkQrBpw==
"@types/markdown-it@^12.2.3":
version "12.2.3"
resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51"
@ -11365,6 +11360,11 @@ ccount@^1.0.0:
resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043"
integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==
ccount@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5"
integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==
chai-as-promised@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0"
@ -13967,6 +13967,11 @@ escape-string-regexp@^2.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
escape-string-regexp@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
escodegen@^1.13.0:
version "1.14.3"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
@ -19271,6 +19276,11 @@ long@^5.0.0:
resolved "https://registry.yarnpkg.com/long/-/long-5.2.1.tgz#e27595d0083d103d2fa2c20c7699f8e0c92b897f"
integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==
longest-streak@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4"
integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@ -19512,11 +19522,6 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
markdown-escape@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/markdown-escape/-/markdown-escape-2.0.0.tgz#44484d30d7845b91575c77fd8898f23a0a6f890c"
integrity sha512-Trz4v0+XWlwy68LJIyw3bLbsJiC8XAbRCKF9DbEtZjyndKOGVx6n+wNB0VfoRmY2LKboQLeniap3xrb6LGSJ8A==
markdown-escapes@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535"
@ -19549,6 +19554,11 @@ markdown-it@^13.0.1:
mdurl "^1.0.1"
uc.micro "^1.0.5"
markdown-table@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.3.tgz#e6331d30e493127e031dd385488b5bd326e4a6bd"
integrity sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==
markdown-to-jsx@^7.1.3:
version "7.1.7"
resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.1.7.tgz#a5f22102fb12241c8cea1ca6a4050bb76b23a25d"
@ -19600,6 +19610,16 @@ mdast-util-definitions@^5.0.0:
"@types/unist" "^2.0.0"
unist-util-visit "^4.0.0"
mdast-util-find-and-replace@^2.0.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz#cc2b774f7f3630da4bd592f61966fecade8b99b1"
integrity sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==
dependencies:
"@types/mdast" "^3.0.0"
escape-string-regexp "^5.0.0"
unist-util-is "^5.0.0"
unist-util-visit-parents "^5.0.0"
mdast-util-from-markdown@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.0.tgz#0214124154f26154a2b3f9d401155509be45e894"
@ -19618,6 +19638,72 @@ mdast-util-from-markdown@^1.0.0:
unist-util-stringify-position "^3.0.0"
uvu "^0.5.0"
mdast-util-gfm-autolink-literal@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz#67a13abe813d7eba350453a5333ae1bc0ec05c06"
integrity sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==
dependencies:
"@types/mdast" "^3.0.0"
ccount "^2.0.0"
mdast-util-find-and-replace "^2.0.0"
micromark-util-character "^1.0.0"
mdast-util-gfm-footnote@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz#ce5e49b639c44de68d5bf5399877a14d5020424e"
integrity sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-to-markdown "^1.3.0"
micromark-util-normalize-identifier "^1.0.0"
mdast-util-gfm-strikethrough@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz#5470eb105b483f7746b8805b9b989342085795b7"
integrity sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-to-markdown "^1.3.0"
mdast-util-gfm-table@^1.0.0:
version "1.0.7"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz#3552153a146379f0f9c4c1101b071d70bbed1a46"
integrity sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==
dependencies:
"@types/mdast" "^3.0.0"
markdown-table "^3.0.0"
mdast-util-from-markdown "^1.0.0"
mdast-util-to-markdown "^1.3.0"
mdast-util-gfm-task-list-item@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz#b280fcf3b7be6fd0cc012bbe67a59831eb34097b"
integrity sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-to-markdown "^1.3.0"
mdast-util-gfm@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz#e92f4d8717d74bdba6de57ed21cc8b9552e2d0b6"
integrity sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==
dependencies:
mdast-util-from-markdown "^1.0.0"
mdast-util-gfm-autolink-literal "^1.0.0"
mdast-util-gfm-footnote "^1.0.0"
mdast-util-gfm-strikethrough "^1.0.0"
mdast-util-gfm-table "^1.0.0"
mdast-util-gfm-task-list-item "^1.0.0"
mdast-util-to-markdown "^1.0.0"
mdast-util-phrasing@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz#c7c21d0d435d7fb90956038f02e8702781f95463"
integrity sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==
dependencies:
"@types/mdast" "^3.0.0"
unist-util-is "^5.0.0"
mdast-util-to-hast@10.0.1:
version "10.0.1"
resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz#0cfc82089494c52d46eb0e3edb7a4eb2aea021eb"
@ -19646,11 +19732,32 @@ mdast-util-to-hast@^12.1.0:
unist-util-position "^4.0.0"
unist-util-visit "^4.0.0"
mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz#c13343cb3fc98621911d33b5cd42e7d0731171c6"
integrity sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==
dependencies:
"@types/mdast" "^3.0.0"
"@types/unist" "^2.0.0"
longest-streak "^3.0.0"
mdast-util-phrasing "^3.0.0"
mdast-util-to-string "^3.0.0"
micromark-util-decode-string "^1.0.0"
unist-util-visit "^4.0.0"
zwitch "^2.0.0"
mdast-util-to-string@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz#27055500103f51637bd07d01da01eb1967a43527"
integrity sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==
mdast-util-to-string@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz#66f7bb6324756741c5f47a53557f0cbf16b6f789"
integrity sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-to-string@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.1.tgz#db859050d79d48cf9896d294de06f3ede7474d16"
@ -19779,7 +19886,7 @@ microevent.ts@~0.1.1:
resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0"
integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==
micromark-core-commonmark@^1.0.1:
micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1:
version "1.0.6"
resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad"
integrity sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==
@ -19801,6 +19908,86 @@ micromark-core-commonmark@^1.0.1:
micromark-util-types "^1.0.1"
uvu "^0.5.0"
micromark-extension-gfm-autolink-literal@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.3.tgz#dc589f9c37eaff31a175bab49f12290edcf96058"
integrity sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-sanitize-uri "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-extension-gfm-footnote@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.4.tgz#cbfd8873b983e820c494498c6dac0105920818d5"
integrity sha512-E/fmPmDqLiMUP8mLJ8NbJWJ4bTw6tS+FEQS8CcuDtZpILuOb2kjLqPEeAePF1djXROHXChM/wPJw0iS4kHCcIg==
dependencies:
micromark-core-commonmark "^1.0.0"
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-normalize-identifier "^1.0.0"
micromark-util-sanitize-uri "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-extension-gfm-strikethrough@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.5.tgz#4db40b87d674a6fe1d00d59ac91118e4f5960f12"
integrity sha512-X0oI5eYYQVARhiNfbETy7BfLSmSilzN1eOuoRnrf9oUNsPRrWOAe9UqSizgw1vNxQBfOwL+n2610S3bYjVNi7w==
dependencies:
micromark-util-chunked "^1.0.0"
micromark-util-classify-character "^1.0.0"
micromark-util-resolve-all "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-extension-gfm-table@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz#7b708b728f8dc4d95d486b9e7a2262f9cddbcbb4"
integrity sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg==
dependencies:
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-extension-gfm-tagfilter@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz#aa7c4dd92dabbcb80f313ebaaa8eb3dac05f13a7"
integrity sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==
dependencies:
micromark-util-types "^1.0.0"
micromark-extension-gfm-task-list-item@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.4.tgz#4b66d87847de40cef2b5ceddb9f9629a6dfe7472"
integrity sha512-9XlIUUVnYXHsFF2HZ9jby4h3npfX10S1coXTnV035QGPgrtNYQq3J6IfIvcCIUAJrrqBVi5BqA/LmaOMJqPwMQ==
dependencies:
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-extension-gfm@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-2.0.1.tgz#40f3209216127a96297c54c67f5edc7ef2d1a2a2"
integrity sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA==
dependencies:
micromark-extension-gfm-autolink-literal "^1.0.0"
micromark-extension-gfm-footnote "^1.0.0"
micromark-extension-gfm-strikethrough "^1.0.0"
micromark-extension-gfm-table "^1.0.0"
micromark-extension-gfm-tagfilter "^1.0.0"
micromark-extension-gfm-task-list-item "^1.0.0"
micromark-util-combine-extensions "^1.0.0"
micromark-util-types "^1.0.0"
micromark-factory-destination@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz#fef1cb59ad4997c496f887b6977aa3034a5a277e"
@ -24121,6 +24308,16 @@ remark-footnotes@2.0.0:
resolved "https://registry.yarnpkg.com/remark-footnotes/-/remark-footnotes-2.0.0.tgz#9001c4c2ffebba55695d2dd80ffb8b82f7e6303f"
integrity sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==
remark-gfm@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f"
integrity sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-gfm "^2.0.0"
micromark-extension-gfm "^2.0.0"
unified "^10.0.0"
remark-mdx@1.6.22:
version "1.6.22"
resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.6.22.tgz#06a8dab07dcfdd57f3373af7f86bd0e992108bbd"
@ -26974,7 +27171,7 @@ unist-util-visit-parents@^3.0.0:
"@types/unist" "^2.0.0"
unist-util-is "^4.0.0"
unist-util-visit-parents@^5.1.1:
unist-util-visit-parents@^5.0.0, unist-util-visit-parents@^5.1.1:
version "5.1.3"
resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz#b4520811b0ca34285633785045df7a8d6776cfeb"
integrity sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==
@ -28295,3 +28492,8 @@ zwitch@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"
integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==
zwitch@^2.0.0:
version "2.0.4"
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7"
integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==