···11+{
22+ "lexicon": 1,
33+ "id": "network.cosmik.card",
44+ "description": "A single record type for all cards.",
55+ "defs": {
66+ "main": {
77+ "type": "record",
88+ "description": "A record representing a card with content.",
99+ "key": "tid",
1010+ "record": {
1111+ "type": "object",
1212+ "required": ["type", "content"],
1313+ "properties": {
1414+ "type": {
1515+ "type": "string",
1616+ "description": "The type of card",
1717+ "knownValues": ["URL", "NOTE"]
1818+ },
1919+ "content": {
2020+ "type": "union",
2121+ "description": "The specific content of the card, determined by the card type.",
2222+ "refs": ["#urlContent", "#noteContent"]
2323+ },
2424+ "url": {
2525+ "type": "string",
2626+ "format": "uri",
2727+ "description": "Optional URL associated with the card. Required for URL cards, optional for NOTE cards."
2828+ },
2929+ "parentCard": {
3030+ "type": "ref",
3131+ "description": "Optional strong reference to a parent card (for NOTE cards).",
3232+ "ref": "com.atproto.repo.strongRef"
3333+ },
3434+ "createdAt": {
3535+ "type": "string",
3636+ "format": "datetime",
3737+ "description": "Timestamp when this card was created (usually set by PDS)."
3838+ },
3939+ "originalCard": {
4040+ "type": "ref",
4141+ "description": "Optional strong reference to the original card (for NOTE cards).",
4242+ "ref": "com.atproto.repo.strongRef"
4343+ },
4444+ "provenance": {
4545+ "type": "ref",
4646+ "description": "Optional provenance information for this card.",
4747+ "ref": "network.cosmik.defs#provenance"
4848+ }
4949+ }
5050+ }
5151+ },
5252+ "urlContent": {
5353+ "type": "object",
5454+ "description": "Content structure for a URL card.",
5555+ "required": ["url"],
5656+ "properties": {
5757+ "url": {
5858+ "type": "string",
5959+ "format": "uri",
6060+ "description": "The URL being saved"
6161+ },
6262+ "metadata": {
6363+ "type": "ref",
6464+ "ref": "#urlMetadata",
6565+ "description": "Optional metadata about the URL"
6666+ }
6767+ }
6868+ },
6969+ "noteContent": {
7070+ "type": "object",
7171+ "description": "Content structure for a note card.",
7272+ "required": ["text"],
7373+ "properties": {
7474+ "text": {
7575+ "type": "string",
7676+ "description": "The note text content",
7777+ "maxLength": 10000
7878+ }
7979+ }
8080+ },
8181+ "urlMetadata": {
8282+ "type": "object",
8383+ "description": "Metadata about a URL.",
8484+ "properties": {
8585+ "title": {
8686+ "type": "string",
8787+ "description": "Title of the page"
8888+ },
8989+ "description": {
9090+ "type": "string",
9191+ "description": "Description of the page"
9292+ },
9393+ "author": {
9494+ "type": "string",
9595+ "description": "Author of the content"
9696+ },
9797+ "publishedDate": {
9898+ "type": "string",
9999+ "format": "datetime",
100100+ "description": "When the content was published"
101101+ },
102102+ "siteName": {
103103+ "type": "string",
104104+ "description": "Name of the site"
105105+ },
106106+ "imageUrl": {
107107+ "type": "string",
108108+ "format": "uri",
109109+ "description": "URL of a representative image"
110110+ },
111111+ "type": {
112112+ "type": "string",
113113+ "description": "Type of content (e.g., 'video', 'article')"
114114+ },
115115+ "retrievedAt": {
116116+ "type": "string",
117117+ "format": "datetime",
118118+ "description": "When the metadata was retrieved"
119119+ },
120120+ "doi": {
121121+ "type": "string",
122122+ "description": "Digital Object Identifier (DOI) for academic content"
123123+ },
124124+ "isbn": {
125125+ "type": "string",
126126+ "description": "International Standard Book Number (ISBN) for books"
127127+ }
128128+ }
129129+ }
130130+ }
131131+}
+51
lexicons/network/cosmik/collection.json
···11+{
22+ "lexicon": 1,
33+ "id": "network.cosmik.collection",
44+ "description": "A single record type for collections of cards.",
55+ "defs": {
66+ "main": {
77+ "type": "record",
88+ "description": "A record representing a collection of cards.",
99+ "key": "tid",
1010+ "record": {
1111+ "type": "object",
1212+ "required": ["name", "accessType"],
1313+ "properties": {
1414+ "name": {
1515+ "type": "string",
1616+ "description": "Name of the collection",
1717+ "maxLength": 100
1818+ },
1919+ "description": {
2020+ "type": "string",
2121+ "description": "Description of the collection",
2222+ "maxLength": 500
2323+ },
2424+ "accessType": {
2525+ "type": "string",
2626+ "description": "Access control for the collection",
2727+ "knownValues": ["OPEN", "CLOSED"]
2828+ },
2929+ "collaborators": {
3030+ "type": "array",
3131+ "description": "List of collaborator DIDs who can add cards to closed collections",
3232+ "items": {
3333+ "type": "string",
3434+ "description": "DID of a collaborator"
3535+ }
3636+ },
3737+ "createdAt": {
3838+ "type": "string",
3939+ "format": "datetime",
4040+ "description": "Timestamp when this collection was created (usually set by PDS)."
4141+ },
4242+ "updatedAt": {
4343+ "type": "string",
4444+ "format": "datetime",
4545+ "description": "Timestamp when this collection was last updated."
4646+ }
4747+ }
4848+ }
4949+ }
5050+ }
5151+}
+52
lexicons/network/cosmik/collectionLink.json
···11+{
22+ "lexicon": 1,
33+ "id": "network.cosmik.collectionLink",
44+ "description": "A record that links a card to a collection.",
55+ "defs": {
66+ "main": {
77+ "type": "record",
88+ "description": "A record representing the relationship between a card and a collection.",
99+ "key": "tid",
1010+ "record": {
1111+ "type": "object",
1212+ "required": ["collection", "card", "addedBy", "addedAt"],
1313+ "properties": {
1414+ "collection": {
1515+ "type": "ref",
1616+ "description": "Strong reference to the collection record.",
1717+ "ref": "com.atproto.repo.strongRef"
1818+ },
1919+ "card": {
2020+ "type": "ref",
2121+ "description": "Strong reference to the card record in the users library.",
2222+ "ref": "com.atproto.repo.strongRef"
2323+ },
2424+ "originalCard": {
2525+ "type": "ref",
2626+ "description": "Strong reference to the original card record (may be in another library).",
2727+ "ref": "com.atproto.repo.strongRef"
2828+ },
2929+ "addedBy": {
3030+ "type": "string",
3131+ "description": "DID of the user who added the card to the collection"
3232+ },
3333+ "addedAt": {
3434+ "type": "string",
3535+ "format": "datetime",
3636+ "description": "Timestamp when the card was added to the collection."
3737+ },
3838+ "createdAt": {
3939+ "type": "string",
4040+ "format": "datetime",
4141+ "description": "Timestamp when this link record was created (usually set by PDS)."
4242+ },
4343+ "provenance": {
4444+ "type": "ref",
4545+ "description": "Optional provenance information for this link.",
4646+ "ref": "network.cosmik.defs#provenance"
4747+ }
4848+ }
4949+ }
5050+ }
5151+ }
5252+}
+18
lexicons/network/cosmik/defs.json
···11+{
22+ "lexicon": 1,
33+ "id": "network.cosmik.defs",
44+ "description": "Common definitions for annotation types and references",
55+ "defs": {
66+ "provenance": {
77+ "type": "object",
88+ "description": "Represents the provenance or source of a record.",
99+ "properties": {
1010+ "via": {
1111+ "type": "ref",
1212+ "description": "Strong reference to the card that led to this record.",
1313+ "ref": "com.atproto.repo.strongRef"
1414+ }
1515+ }
1616+ }
1717+ }
1818+}
···11+export * as ComAtprotoRepoStrongRef from "./types/com/atproto/repo/strongRef.js";
22+export * as NetworkCosmikCard from "./types/network/cosmik/card.js";
33+export * as NetworkCosmikCollection from "./types/network/cosmik/collection.js";
44+export * as NetworkCosmikCollectionLink from "./types/network/cosmik/collectionLink.js";
55+export * as NetworkCosmikDefs from "./types/network/cosmik/defs.js";
+18
src/lexicons/types/com/atproto/repo/strongRef.ts
···11+import type {} from "@atcute/lexicons";
22+import * as v from "@atcute/lexicons/validations";
33+44+const _mainSchema = /*#__PURE__*/ v.object({
55+ $type: /*#__PURE__*/ v.optional(
66+ /*#__PURE__*/ v.literal("com.atproto.repo.strongRef"),
77+ ),
88+ cid: /*#__PURE__*/ v.cidString(),
99+ uri: /*#__PURE__*/ v.resourceUriString(),
1010+});
1111+1212+type main$schematype = typeof _mainSchema;
1313+1414+export interface mainSchema extends main$schematype {}
1515+1616+export const mainSchema = _mainSchema as mainSchema;
1717+1818+export interface Main extends v.InferInput<typeof mainSchema> {}
+146
src/lexicons/types/network/cosmik/card.ts
···11+import type {} from "@atcute/lexicons";
22+import * as v from "@atcute/lexicons/validations";
33+import type {} from "@atcute/lexicons/ambient";
44+import * as ComAtprotoRepoStrongRef from "../../com/atproto/repo/strongRef.js";
55+import * as NetworkCosmikDefs from "./defs.js";
66+77+const _mainSchema = /*#__PURE__*/ v.record(
88+ /*#__PURE__*/ v.tidString(),
99+ /*#__PURE__*/ v.object({
1010+ $type: /*#__PURE__*/ v.literal("network.cosmik.card"),
1111+ /**
1212+ * The specific content of the card, determined by the card type.
1313+ */
1414+ get content() {
1515+ return /*#__PURE__*/ v.variant([noteContentSchema, urlContentSchema]);
1616+ },
1717+ /**
1818+ * Timestamp when this card was created (usually set by PDS).
1919+ */
2020+ createdAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
2121+ /**
2222+ * Optional strong reference to the original card (for NOTE cards).
2323+ */
2424+ get originalCard() {
2525+ return /*#__PURE__*/ v.optional(ComAtprotoRepoStrongRef.mainSchema);
2626+ },
2727+ /**
2828+ * Optional strong reference to a parent card (for NOTE cards).
2929+ */
3030+ get parentCard() {
3131+ return /*#__PURE__*/ v.optional(ComAtprotoRepoStrongRef.mainSchema);
3232+ },
3333+ /**
3434+ * Optional provenance information for this card.
3535+ */
3636+ get provenance() {
3737+ return /*#__PURE__*/ v.optional(NetworkCosmikDefs.provenanceSchema);
3838+ },
3939+ /**
4040+ * The type of card
4141+ */
4242+ type: /*#__PURE__*/ v.string<"NOTE" | "URL" | (string & {})>(),
4343+ /**
4444+ * Optional URL associated with the card. Required for URL cards, optional for NOTE cards.
4545+ */
4646+ url: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.genericUriString()),
4747+ }),
4848+);
4949+const _noteContentSchema = /*#__PURE__*/ v.object({
5050+ $type: /*#__PURE__*/ v.optional(
5151+ /*#__PURE__*/ v.literal("network.cosmik.card#noteContent"),
5252+ ),
5353+ /**
5454+ * The note text content
5555+ * @maxLength 10000
5656+ */
5757+ text: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
5858+ /*#__PURE__*/ v.stringLength(0, 10000),
5959+ ]),
6060+});
6161+const _urlContentSchema = /*#__PURE__*/ v.object({
6262+ $type: /*#__PURE__*/ v.optional(
6363+ /*#__PURE__*/ v.literal("network.cosmik.card#urlContent"),
6464+ ),
6565+ /**
6666+ * Optional metadata about the URL
6767+ */
6868+ get metadata() {
6969+ return /*#__PURE__*/ v.optional(urlMetadataSchema);
7070+ },
7171+ /**
7272+ * The URL being saved
7373+ */
7474+ url: /*#__PURE__*/ v.genericUriString(),
7575+});
7676+const _urlMetadataSchema = /*#__PURE__*/ v.object({
7777+ $type: /*#__PURE__*/ v.optional(
7878+ /*#__PURE__*/ v.literal("network.cosmik.card#urlMetadata"),
7979+ ),
8080+ /**
8181+ * Author of the content
8282+ */
8383+ author: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
8484+ /**
8585+ * Description of the page
8686+ */
8787+ description: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
8888+ /**
8989+ * Digital Object Identifier (DOI) for academic content
9090+ */
9191+ doi: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
9292+ /**
9393+ * URL of a representative image
9494+ */
9595+ imageUrl: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.genericUriString()),
9696+ /**
9797+ * International Standard Book Number (ISBN) for books
9898+ */
9999+ isbn: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
100100+ /**
101101+ * When the content was published
102102+ */
103103+ publishedDate: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
104104+ /**
105105+ * When the metadata was retrieved
106106+ */
107107+ retrievedAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
108108+ /**
109109+ * Name of the site
110110+ */
111111+ siteName: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
112112+ /**
113113+ * Title of the page
114114+ */
115115+ title: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
116116+ /**
117117+ * Type of content (e.g., 'video', 'article')
118118+ */
119119+ type: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
120120+});
121121+122122+type main$schematype = typeof _mainSchema;
123123+type noteContent$schematype = typeof _noteContentSchema;
124124+type urlContent$schematype = typeof _urlContentSchema;
125125+type urlMetadata$schematype = typeof _urlMetadataSchema;
126126+127127+export interface mainSchema extends main$schematype {}
128128+export interface noteContentSchema extends noteContent$schematype {}
129129+export interface urlContentSchema extends urlContent$schematype {}
130130+export interface urlMetadataSchema extends urlMetadata$schematype {}
131131+132132+export const mainSchema = _mainSchema as mainSchema;
133133+export const noteContentSchema = _noteContentSchema as noteContentSchema;
134134+export const urlContentSchema = _urlContentSchema as urlContentSchema;
135135+export const urlMetadataSchema = _urlMetadataSchema as urlMetadataSchema;
136136+137137+export interface Main extends v.InferInput<typeof mainSchema> {}
138138+export interface NoteContent extends v.InferInput<typeof noteContentSchema> {}
139139+export interface UrlContent extends v.InferInput<typeof urlContentSchema> {}
140140+export interface UrlMetadata extends v.InferInput<typeof urlMetadataSchema> {}
141141+142142+declare module "@atcute/lexicons/ambient" {
143143+ interface Records {
144144+ "network.cosmik.card": mainSchema;
145145+ }
146146+}
+58
src/lexicons/types/network/cosmik/collection.ts
···11+import type {} from "@atcute/lexicons";
22+import * as v from "@atcute/lexicons/validations";
33+import type {} from "@atcute/lexicons/ambient";
44+55+const _mainSchema = /*#__PURE__*/ v.record(
66+ /*#__PURE__*/ v.tidString(),
77+ /*#__PURE__*/ v.object({
88+ $type: /*#__PURE__*/ v.literal("network.cosmik.collection"),
99+ /**
1010+ * Access control for the collection
1111+ */
1212+ accessType: /*#__PURE__*/ v.string<"CLOSED" | "OPEN" | (string & {})>(),
1313+ /**
1414+ * List of collaborator DIDs who can add cards to closed collections
1515+ */
1616+ collaborators: /*#__PURE__*/ v.optional(
1717+ /*#__PURE__*/ v.array(/*#__PURE__*/ v.string()),
1818+ ),
1919+ /**
2020+ * Timestamp when this collection was created (usually set by PDS).
2121+ */
2222+ createdAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
2323+ /**
2424+ * Description of the collection
2525+ * @maxLength 500
2626+ */
2727+ description: /*#__PURE__*/ v.optional(
2828+ /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
2929+ /*#__PURE__*/ v.stringLength(0, 500),
3030+ ]),
3131+ ),
3232+ /**
3333+ * Name of the collection
3434+ * @maxLength 100
3535+ */
3636+ name: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
3737+ /*#__PURE__*/ v.stringLength(0, 100),
3838+ ]),
3939+ /**
4040+ * Timestamp when this collection was last updated.
4141+ */
4242+ updatedAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
4343+ }),
4444+);
4545+4646+type main$schematype = typeof _mainSchema;
4747+4848+export interface mainSchema extends main$schematype {}
4949+5050+export const mainSchema = _mainSchema as mainSchema;
5151+5252+export interface Main extends v.InferInput<typeof mainSchema> {}
5353+5454+declare module "@atcute/lexicons/ambient" {
5555+ interface Records {
5656+ "network.cosmik.collection": mainSchema;
5757+ }
5858+}
···11+import type {} from "@atcute/lexicons";
22+import * as v from "@atcute/lexicons/validations";
33+import type {} from "@atcute/lexicons/ambient";
44+import * as ComAtprotoRepoStrongRef from "../../com/atproto/repo/strongRef.js";
55+import * as NetworkCosmikDefs from "./defs.js";
66+77+const _mainSchema = /*#__PURE__*/ v.record(
88+ /*#__PURE__*/ v.tidString(),
99+ /*#__PURE__*/ v.object({
1010+ $type: /*#__PURE__*/ v.literal("network.cosmik.collectionLink"),
1111+ /**
1212+ * Timestamp when the card was added to the collection.
1313+ */
1414+ addedAt: /*#__PURE__*/ v.datetimeString(),
1515+ /**
1616+ * DID of the user who added the card to the collection
1717+ */
1818+ addedBy: /*#__PURE__*/ v.string(),
1919+ /**
2020+ * Strong reference to the card record in the users library.
2121+ */
2222+ get card() {
2323+ return ComAtprotoRepoStrongRef.mainSchema;
2424+ },
2525+ /**
2626+ * Strong reference to the collection record.
2727+ */
2828+ get collection() {
2929+ return ComAtprotoRepoStrongRef.mainSchema;
3030+ },
3131+ /**
3232+ * Timestamp when this link record was created (usually set by PDS).
3333+ */
3434+ createdAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()),
3535+ /**
3636+ * Strong reference to the original card record (may be in another library).
3737+ */
3838+ get originalCard() {
3939+ return /*#__PURE__*/ v.optional(ComAtprotoRepoStrongRef.mainSchema);
4040+ },
4141+ /**
4242+ * Optional provenance information for this link.
4343+ */
4444+ get provenance() {
4545+ return /*#__PURE__*/ v.optional(NetworkCosmikDefs.provenanceSchema);
4646+ },
4747+ }),
4848+);
4949+5050+type main$schematype = typeof _mainSchema;
5151+5252+export interface mainSchema extends main$schematype {}
5353+5454+export const mainSchema = _mainSchema as mainSchema;
5555+5656+export interface Main extends v.InferInput<typeof mainSchema> {}
5757+5858+declare module "@atcute/lexicons/ambient" {
5959+ interface Records {
6060+ "network.cosmik.collectionLink": mainSchema;
6161+ }
6262+}
+23
src/lexicons/types/network/cosmik/defs.ts
···11+import type {} from "@atcute/lexicons";
22+import * as v from "@atcute/lexicons/validations";
33+import * as ComAtprotoRepoStrongRef from "../../com/atproto/repo/strongRef.js";
44+55+const _provenanceSchema = /*#__PURE__*/ v.object({
66+ $type: /*#__PURE__*/ v.optional(
77+ /*#__PURE__*/ v.literal("network.cosmik.defs#provenance"),
88+ ),
99+ /**
1010+ * Strong reference to the card that led to this record.
1111+ */
1212+ get via() {
1313+ return /*#__PURE__*/ v.optional(ComAtprotoRepoStrongRef.mainSchema);
1414+ },
1515+});
1616+1717+type provenance$schematype = typeof _provenanceSchema;
1818+1919+export interface provenanceSchema extends provenance$schematype {}
2020+2121+export const provenanceSchema = _provenanceSchema as provenanceSchema;
2222+2323+export interface Provenance extends v.InferInput<typeof provenanceSchema> {}
+28
src/lib.ts
···11+import type { Client } from "@atcute/client";
22+import type { ActorIdentifier, Nsid } from "@atcute/lexicons";
33+44+export async function getProfile(client: Client, actor: string) {
55+ return await client.get("app.bsky.actor.getProfile", {
66+ params: { actor: actor as ActorIdentifier },
77+ });
88+}
99+1010+export async function getCollections(client: Client, repo: string) {
1111+ return await client.get("com.atproto.repo.listRecords", {
1212+ params: {
1313+ repo: repo as ActorIdentifier,
1414+ collection: "network.cosmik.collection" as Nsid,
1515+ limit: 100,
1616+ },
1717+ });
1818+}
1919+2020+export async function getCards(client: Client, repo: string) {
2121+ return await client.get("com.atproto.repo.listRecords", {
2222+ params: {
2323+ repo: repo as ActorIdentifier,
2424+ collection: "network.cosmik.card" as Nsid,
2525+ limit: 100,
2626+ },
2727+ });
2828+}
+82-68
src/main.ts
···11-import {App, Editor, MarkdownView, Modal, Notice, Plugin} from 'obsidian';
22-import {DEFAULT_SETTINGS, MyPluginSettings, SampleSettingTab} from "./settings";
33-44-// Remember to rename these classes and interfaces!
11+import { Notice, Plugin, WorkspaceLeaf } from "obsidian";
22+import type { Client } from "@atcute/client";
33+import { DEFAULT_SETTINGS, AtProtoSettings, SettingTab } from "./settings";
44+import { createAuthenticatedClient, createPublicClient } from "./auth";
55+import { getCollections } from "./lib";
66+import { SembleCollectionsView, VIEW_TYPE_SEMBLE_COLLECTIONS } from "views/collections";
5768export default class MyPlugin extends Plugin {
77- settings: MyPluginSettings;
99+ settings: AtProtoSettings = DEFAULT_SETTINGS;
1010+ client: Client | null = null;
811912 async onload() {
1013 await this.loadSettings();
1414+ await this.initClient();
11151212- // This creates an icon in the left ribbon.
1313- this.addRibbonIcon('dice', 'Sample', (evt: MouseEvent) => {
1414- // Called when the user clicks the icon.
1515- new Notice('This is a notice!');
1616+ this.registerView(VIEW_TYPE_SEMBLE_COLLECTIONS, (leaf) => {
1717+ return new SembleCollectionsView(leaf, this);
1618 });
17191818- // This adds a status bar item to the bottom of the app. Does not work on mobile apps.
1919- const statusBarItemEl = this.addStatusBarItem();
2020- statusBarItemEl.setText('Status bar text');
21202222- // This adds a simple command that can be triggered anywhere
2321 this.addCommand({
2424- id: 'open-modal-simple',
2525- name: 'Open modal (simple)',
2626- callback: () => {
2727- new SampleModal(this.app).open();
2828- }
2222+ id: "list-collections",
2323+ name: "List Collections",
2424+ callback: () => this.listCollections(),
2925 });
3030- // This adds an editor command that can perform some operation on the current editor instance
2626+3127 this.addCommand({
3232- id: 'replace-selected',
3333- name: 'Replace selected content',
3434- editorCallback: (editor: Editor, view: MarkdownView) => {
3535- editor.replaceSelection('Sample editor command');
3636- }
2828+ id: "view-semble-collections",
2929+ name: "View Semble Collections",
3030+ callback: () => this.activateView(VIEW_TYPE_SEMBLE_COLLECTIONS),
3731 });
3838- // This adds a complex command that can check whether the current state of the app allows execution of the command
3939- this.addCommand({
4040- id: 'open-modal-complex',
4141- name: 'Open modal (complex)',
4242- checkCallback: (checking: boolean) => {
4343- // Conditions to check
4444- const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
4545- if (markdownView) {
4646- // If checking is true, we're simply "checking" if the command can be run.
4747- // If checking is false, then we want to actually perform the operation.
4848- if (!checking) {
4949- new SampleModal(this.app).open();
5050- }
3232+3333+ this.addSettingTab(new SettingTab(this.app, this));
3434+ }
3535+51365252- // This command will only show up in Command Palette when the check function returns true
5353- return true;
5454- }
5555- return false;
3737+ private async initClient() {
3838+ const { identifier, appPassword } = this.settings;
3939+ if (identifier && appPassword) {
4040+ try {
4141+ this.client = await createAuthenticatedClient({ identifier, password: appPassword });
4242+ new Notice("Connected to Bluesky");
4343+ } catch (e) {
4444+ new Notice(`Auth failed: ${e}`);
4545+ this.client = createPublicClient();
5646 }
5757- });
4747+ } else {
4848+ this.client = createPublicClient();
4949+ }
5050+ }
58515959- // This adds a settings tab so the user can configure various aspects of the plugin
6060- this.addSettingTab(new SampleSettingTab(this.app, this));
5252+ async refreshClient() {
5353+ await this.initClient();
5454+ }
61556262- // If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
6363- // Using this function will automatically remove the event listener when this plugin is disabled.
6464- this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
6565- new Notice("Click");
6666- });
5656+ private async listCollections() {
5757+ if (!this.client) return;
67586868- // When registering intervals, this function will automatically clear the interval when the plugin is disabled.
6969- this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
5959+ const repo = this.settings.identifier
70606161+ try {
6262+ const resp = await getCollections(this.client, repo);
6363+ if (!resp.ok) {
6464+ new Notice(`Failed: ${resp.data?.error}`);
6565+ return;
6666+ }
6767+ if (resp.data.records.length === 0) {
6868+ new Notice("No collections found");
6969+ return;
7070+ }
7171+ console.log("Collections:", resp.data.records);
7272+ new Notice(`Found ${resp.data.records.length} collections`);
7373+ } catch (e) {
7474+ new Notice(`Failed: ${e}`);
7575+ }
7176 }
72777373- onunload() {
7878+ async activateView(v: string) {
7979+ const { workspace } = this.app;
8080+8181+ let leaf: WorkspaceLeaf | null = null;
8282+ const leaves = workspace.getLeavesOfType(v);
8383+8484+ if (leaves.length > 0) {
8585+ console.log("Found existing leaves:", leaves);
8686+ // A leaf with our view already exists, use that
8787+ leaf = leaves[0] as WorkspaceLeaf;
8888+ workspace.revealLeaf(leaf);
8989+ return;
9090+ }
9191+9292+ // Our view could not be found in the workspace, create a new leaf
9393+ // in the right sidebar for it
9494+ // leaf = workspace.getRightLeaf(false);
9595+ leaf = workspace.getMostRecentLeaf()
9696+ await leaf?.setViewState({ type: v, active: true });
9797+9898+ // "Reveal" the leaf in case it is in a collapsed sidebar
9999+ if (leaf) {
100100+ workspace.revealLeaf(leaf);
101101+ }
74102 }
7510376104 async loadSettings() {
7777- this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData() as Partial<MyPluginSettings>);
105105+ this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
78106 }
7910780108 async saveSettings() {
81109 await this.saveData(this.settings);
82110 }
8383-}
841118585-class SampleModal extends Modal {
8686- constructor(app: App) {
8787- super(app);
8888- }
8989-9090- onOpen() {
9191- let {contentEl} = this;
9292- contentEl.setText('Woah!');
9393- }
9494-9595- onClose() {
9696- const {contentEl} = this;
9797- contentEl.empty();
9898- }
112112+ onunload() { }
99113}