github-stars-organizer 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/app/assets/{backups-r4Hq-y_s.js → backups-DrK5WGqD.js} +1 -1
  2. package/dist/app/assets/badge-Drt9JvOu.js +1 -0
  3. package/dist/app/assets/{button-C0MQwO-R.js → button-r9cVFa0_.js} +3 -3
  4. package/dist/app/assets/coerce-Cxjr6MIU.js +1 -0
  5. package/dist/app/assets/{esm-Cyyp48ez.js → esm-CVXsiVX8.js} +1 -1
  6. package/dist/app/assets/explore-Da5fm3tF.js +33 -0
  7. package/dist/app/assets/{history-OZ9l4TiG.js → history-CN5yGwhZ.js} +1 -1
  8. package/dist/app/assets/index-B-eCk0oM.js +10 -0
  9. package/dist/app/assets/index-DIdY6bcj.css +2 -0
  10. package/dist/app/assets/list._listId-CNuYrPaQ.js +2 -0
  11. package/dist/app/assets/list._listId-DBB3l--n.js +1 -0
  12. package/dist/app/assets/{local-backups-BGSAd5Gu.js → local-backups-DLhiWDk4.js} +1 -1
  13. package/dist/app/assets/{local-sync-Dd3hEb9I.js → local-sync-DiQe8mhd.js} +1 -1
  14. package/dist/app/assets/registry-BKf8LDk2.js +4 -0
  15. package/dist/app/assets/routes-C0Cvc6Pi.js +2 -0
  16. package/dist/app/assets/routes-CY3o7jPt.js +3 -0
  17. package/dist/app/assets/{schemas-B0gCwksU.js → schemas-DVvZEnxp.js} +1 -1
  18. package/dist/app/assets/star-BPue5Y4t.js +7 -0
  19. package/dist/app/assets/{triangle-alert-Cgw2r-Xm.js → triangle-alert-BL8M65pd.js} +1 -1
  20. package/dist/app/index.html +10 -10
  21. package/dist/cli.js +475 -1
  22. package/package.json +1 -1
  23. package/dist/app/assets/badge-DWmLT6OI.js +0 -1
  24. package/dist/app/assets/coerce-D595RIhb.js +0 -1
  25. package/dist/app/assets/explore-Cizp4zKW.js +0 -33
  26. package/dist/app/assets/index-BD7Q-Iqo.js +0 -10
  27. package/dist/app/assets/index-DR-cW8P1.css +0 -2
  28. package/dist/app/assets/list._listId-C5TBL1sd.js +0 -2
  29. package/dist/app/assets/list._listId-Cq8rSqKM.js +0 -1
  30. package/dist/app/assets/registry-DZ4hp3Pl.js +0 -4
  31. package/dist/app/assets/routes-C8TmhzRl.js +0 -2
  32. package/dist/app/assets/routes-CXgqVl-F.js +0 -3
  33. package/dist/app/assets/star-BoN7NVgv.js +0 -7
  34. /package/dist/app/assets/{sync-persistence-f8LlQoHO.js → sync-persistence-BJbWXISF.js} +0 -0
package/dist/cli.js CHANGED
@@ -668,6 +668,429 @@ function withItems(graphql, lists) {
668
668
  async function fetchViewerLists(graphql) {
669
669
  return withItems(graphql, await fetchListNodes(graphql, VIEWER_LISTS_QUERY, null));
670
670
  }
671
+ var README_LEAD_CHARS = 4e3;
672
+ var PER_PAGE_LIMIT = 30;
673
+ var RESULT_LIMIT = 8;
674
+ var MIN_STARS = 10;
675
+ var DAY_MS$1 = 864e5;
676
+ var MIN_SCORE = 2.5;
677
+ var LIST_NAME = /awesome|dotfiles|^\.?config|examples|templates|cookbook|tips|resources|curated|^free-for/i;
678
+ var LIST_DESCRIPTION = /curated list|list of|collection of|my (dotfiles|config|setup)/i;
679
+ var BROAD_TOPICS = new Set([
680
+ "javascript",
681
+ "typescript",
682
+ "python",
683
+ "python3",
684
+ "go",
685
+ "golang",
686
+ "rust",
687
+ "java",
688
+ "kotlin",
689
+ "swift",
690
+ "c",
691
+ "cpp",
692
+ "c-plus-plus",
693
+ "csharp",
694
+ "dotnet",
695
+ "php",
696
+ "ruby",
697
+ "scala",
698
+ "elixir",
699
+ "haskell",
700
+ "lua",
701
+ "shell",
702
+ "bash",
703
+ "zsh",
704
+ "nodejs",
705
+ "node",
706
+ "node-js",
707
+ "deno",
708
+ "react",
709
+ "reactjs",
710
+ "vue",
711
+ "vuejs",
712
+ "svelte",
713
+ "sveltekit",
714
+ "nextjs",
715
+ "angular",
716
+ "flutter",
717
+ "dart",
718
+ "html",
719
+ "css",
720
+ "tailwindcss",
721
+ "cli",
722
+ "terminal",
723
+ "command-line",
724
+ "command-line-tool",
725
+ "tool",
726
+ "tools",
727
+ "library",
728
+ "framework",
729
+ "api",
730
+ "rest-api",
731
+ "app",
732
+ "application",
733
+ "core",
734
+ "main",
735
+ "web",
736
+ "webapp",
737
+ "website",
738
+ "server",
739
+ "client",
740
+ "linux",
741
+ "macos",
742
+ "windows",
743
+ "android",
744
+ "ios",
745
+ "mobile",
746
+ "mobile-app",
747
+ "desktop",
748
+ "cross-platform",
749
+ "docker",
750
+ "kubernetes",
751
+ "self-hosted",
752
+ "selfhosted",
753
+ "open-source",
754
+ "opensource",
755
+ "free",
756
+ "hacktoberfest",
757
+ "awesome",
758
+ "awesome-list",
759
+ "list",
760
+ "github",
761
+ "git",
762
+ "productivity",
763
+ "utility",
764
+ "ai",
765
+ "llm",
766
+ "machine-learning",
767
+ "deep-learning",
768
+ "artificial-intelligence",
769
+ "chatgpt",
770
+ "openai",
771
+ "browser",
772
+ "database",
773
+ "backend",
774
+ "frontend",
775
+ "fullstack",
776
+ "devops",
777
+ "security",
778
+ "automation",
779
+ "javascript-library",
780
+ "typescript-library",
781
+ "python-library",
782
+ "npm",
783
+ "pypi",
784
+ "crate",
785
+ "plugin"
786
+ ]);
787
+ var STOPWORDS = new Set([
788
+ "a",
789
+ "an",
790
+ "the",
791
+ "and",
792
+ "or",
793
+ "for",
794
+ "of",
795
+ "to",
796
+ "in",
797
+ "on",
798
+ "with",
799
+ "by",
800
+ "from",
801
+ "as",
802
+ "at",
803
+ "is",
804
+ "are",
805
+ "be",
806
+ "it",
807
+ "its",
808
+ "that",
809
+ "this",
810
+ "your",
811
+ "you",
812
+ "into",
813
+ "via",
814
+ "using",
815
+ "use",
816
+ "based",
817
+ "written",
818
+ "simple",
819
+ "fast",
820
+ "blazing",
821
+ "modern",
822
+ "lightweight",
823
+ "tiny",
824
+ "small",
825
+ "powerful",
826
+ "easy",
827
+ "minimal",
828
+ "beautiful",
829
+ "highly",
830
+ "customizable",
831
+ "open",
832
+ "source",
833
+ "free",
834
+ "high",
835
+ "performance",
836
+ "best",
837
+ "new",
838
+ "awesome",
839
+ "official",
840
+ "library",
841
+ "tool",
842
+ "tools",
843
+ "app",
844
+ "project",
845
+ "framework",
846
+ "implementation",
847
+ "collection",
848
+ "solution",
849
+ "way",
850
+ "just",
851
+ "like",
852
+ "clone",
853
+ "alternative",
854
+ "replacement",
855
+ "supercharge",
856
+ "even",
857
+ "works",
858
+ "entire",
859
+ "made",
860
+ "command-line",
861
+ "command",
862
+ "line",
863
+ "cli",
864
+ "user-friendly",
865
+ "cross-platform",
866
+ "fancy",
867
+ "system",
868
+ "platform",
869
+ "code",
870
+ "elements",
871
+ "linux",
872
+ "macos",
873
+ "windows",
874
+ "can",
875
+ "will",
876
+ "also",
877
+ "all",
878
+ "any",
879
+ "get",
880
+ "make",
881
+ "run",
882
+ "running",
883
+ "see",
884
+ "more",
885
+ "other",
886
+ "one",
887
+ "software",
888
+ "support",
889
+ "supports",
890
+ "feature",
891
+ "features",
892
+ "install",
893
+ "installation",
894
+ "using",
895
+ "about",
896
+ "how",
897
+ "what",
898
+ "which",
899
+ "when",
900
+ "there",
901
+ "here",
902
+ "they",
903
+ "them",
904
+ "their",
905
+ "our",
906
+ "we",
907
+ "has",
908
+ "have",
909
+ "not",
910
+ "but",
911
+ "if",
912
+ "so",
913
+ "up",
914
+ "out",
915
+ "only",
916
+ "most",
917
+ "some",
918
+ "such",
919
+ "than",
920
+ "then",
921
+ "these",
922
+ "those",
923
+ "very",
924
+ "well",
925
+ "want",
926
+ "need",
927
+ "needs",
928
+ "please",
929
+ "note",
930
+ "help",
931
+ "docs",
932
+ "documentation",
933
+ "license",
934
+ "contributing",
935
+ "contributors",
936
+ "release",
937
+ "releases",
938
+ "version",
939
+ "download",
940
+ "build",
941
+ "github",
942
+ "com",
943
+ "www",
944
+ "readme"
945
+ ]);
946
+ function parseTopics(topics) {
947
+ return topics?.split(",").map((t) => t.trim()).filter(Boolean) ?? [];
948
+ }
949
+ function ownNames(source) {
950
+ const [owner, name] = source.full_name.toLowerCase().split("/");
951
+ const project = BROAD_TOPICS.has(name) ? owner : name;
952
+ const joined = project.replace(/[-_.]/g, "");
953
+ return joined === project ? [project] : [project, joined];
954
+ }
955
+ function mentionsOwnName(text, names) {
956
+ const lower = text.toLowerCase();
957
+ return names.some((n) => new RegExp(`(^|[^a-z0-9])${n.replace(/[.]/g, "\\.")}([^a-z0-9]|$)`).test(lower));
958
+ }
959
+ function hasWord(words, part) {
960
+ return words.findIndex((w) => w === part || w === `${part}s` || w === part.replace(/s$/, "") || w.split("-").includes(part));
961
+ }
962
+ function specificTopics(source) {
963
+ const language = source.language?.toLowerCase();
964
+ const names = ownNames(source);
965
+ const words = descriptionWords(source.description);
966
+ return parseTopics(source.topics).filter((t) => !BROAD_TOPICS.has(t) && t !== language && !mentionsOwnName(t, names)).map((topic) => {
967
+ const parts = topic.split("-").filter((part) => !STOPWORDS.has(part));
968
+ const positions = parts.map((part) => hasWord(words, part)).filter((i) => i >= 0);
969
+ const fraction = positions.length / parts.length;
970
+ const first = positions.length > 0 ? Math.min(...positions) : words.length;
971
+ return {
972
+ topic,
973
+ fraction,
974
+ relevance: 3 * fraction + .3 * Math.min(parts.length, 3) - .05 * first
975
+ };
976
+ }).filter((t) => t.fraction > 0).sort((a, b) => b.relevance - a.relevance).map((t) => t.topic);
977
+ }
978
+ function readmeLead(markdown) {
979
+ return markdown.replace(/```[\s\S]*?```/g, " ").replace(/<!--[\s\S]*?-->/g, " ").replace(/<[^>]+>/g, " ").replace(/!\[[^\]]*\]\([^)]*\)/g, " ").replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/https?:\/\/\S+/g, " ").replace(/`[^`]*`/g, " ").replace(/&[a-z]+;|&#\d+;/g, " ").slice(0, README_LEAD_CHARS);
980
+ }
981
+ function keyWords(source) {
982
+ const names = ownNames(source);
983
+ const language = source.language?.toLowerCase();
984
+ const described = descriptionWords(source.description).filter((w) => !mentionsOwnName(w, names) && w !== language);
985
+ const counts = /* @__PURE__ */ new Map();
986
+ for (const w of source.readme ? wordsOf(source.readme) : []) if (!mentionsOwnName(w, names) && w !== language) counts.set(w, (counts.get(w) ?? 0) + 1);
987
+ const fromReadme = [...counts.entries()].filter(([w, n]) => n >= 3 && !described.includes(w)).sort((a, b) => b[1] - a[1]).map(([w]) => w);
988
+ const rank = (w) => counts.get(w) ?? 0;
989
+ const hasReadme = counts.size > 0;
990
+ return [...described.map((w, i) => ({
991
+ w,
992
+ score: (hasReadme ? 2 * rank(w) + 4 : 100) - .1 * i
993
+ })), ...fromReadme.map((w, i) => ({
994
+ w,
995
+ score: rank(w) - .1 * i
996
+ }))].sort((a, b) => b.score - a.score).map(({ w }) => w);
997
+ }
998
+ function wordsOf(text) {
999
+ return text.toLowerCase().replace(/:[a-z0-9_+-]+:/g, " ").split(/[^a-z0-9+#.-]+/).map((w) => w.replace(/^[.-]+|[.-]+$/g, "")).filter((w) => w.length > 2 && /[a-z]/.test(w) && !STOPWORDS.has(w));
1000
+ }
1001
+ function descriptionWords(description) {
1002
+ if (!description) return [];
1003
+ const words = description.toLowerCase().replace(/:[a-z0-9_+-]+:/g, " ").replace(/\([^)]*\)/g, " ").split(/[^a-z0-9+#.-]+/).map((w) => w.replace(/^[.-]+|[.-]+$/g, "")).filter((w) => w.length > 1 && /[a-z]/.test(w) && !STOPWORDS.has(w));
1004
+ return [...new Set(words)];
1005
+ }
1006
+ function minStars(source) {
1007
+ return Math.round(Math.min(300, Math.max(MIN_STARS, source.stars / 200)));
1008
+ }
1009
+ function buildQueries(source) {
1010
+ const filters = `fork:false archived:false stars:>=${minStars(source)}`;
1011
+ const topics = specificTopics(source);
1012
+ const names = ownNames(source);
1013
+ const topicWords = new Set(topics.flatMap((t) => t.split("-")));
1014
+ const words = keyWords(source).map((w, i) => ({
1015
+ w,
1016
+ rank: (topicWords.has(w) ? 0 : 10) + i
1017
+ })).sort((a, b) => a.rank - b.rank).map(({ w }) => w).slice(0, 2);
1018
+ const queries = [];
1019
+ if (topics.length >= 1) queries.push({
1020
+ kind: "topic",
1021
+ q: `topic:${topics[0]} ${filters}`,
1022
+ sort: "stars"
1023
+ });
1024
+ if (words.length >= 2) queries.push({
1025
+ kind: "words",
1026
+ q: `${words.join(" ")} in:name,description,topics ${filters}`,
1027
+ sort: "best-match"
1028
+ });
1029
+ queries.push({
1030
+ kind: "readme",
1031
+ q: `${names[0]} in:readme ${words[0] ?? ""} ${filters}`.replace(/\s+/g, " "),
1032
+ sort: "stars"
1033
+ });
1034
+ return queries.slice(0, 3);
1035
+ }
1036
+ function overlap(a, b) {
1037
+ return a.filter((x) => b.has(x)).length;
1038
+ }
1039
+ function rankSimilar(source, results, now = Date.now()) {
1040
+ const self = source.full_name.toLowerCase();
1041
+ const sourceTopics = parseTopics(source.topics);
1042
+ const specific = new Set(specificTopics(source));
1043
+ const sourceWords = new Set(keyWords(source).slice(0, 12));
1044
+ const names = ownNames(source);
1045
+ const pool = /* @__PURE__ */ new Map();
1046
+ for (const { kind, items } of results) for (const item of items.slice(0, PER_PAGE_LIMIT)) {
1047
+ const key = item.full_name.toLowerCase();
1048
+ if (key === self || item.fork || item.archived) continue;
1049
+ const entry = pool.get(key) ?? {
1050
+ item,
1051
+ hits: 0,
1052
+ comparesItself: false
1053
+ };
1054
+ entry.hits++;
1055
+ if (kind === "readme") entry.comparesItself = true;
1056
+ pool.set(key, entry);
1057
+ }
1058
+ const maxStars = Math.max(1, ...[...pool.values()].map(({ item }) => item.stargazers_count));
1059
+ const related = [...pool.values()].map(({ item, hits, comparesItself }) => {
1060
+ const topics = item.topics ?? [];
1061
+ const topicSet = new Set(topics);
1062
+ const shared = sourceTopics.filter((t) => topicSet.has(t));
1063
+ const sharedSpecific = shared.filter((t) => specific.has(t));
1064
+ const words = [...descriptionWords(item.description), ...topics.flatMap((t) => t.split("-"))];
1065
+ const wordOverlap = sourceWords.size > 0 ? overlap(words, sourceWords) / Math.sqrt(sourceWords.size * Math.max(1, words.length)) : 0;
1066
+ const days = item.pushed_at ? (now - Date.parse(item.pushed_at)) / DAY_MS$1 : Infinity;
1067
+ const addOn = mentionsOwnName(`${item.full_name.split("/")[1]} ${item.description ?? ""}`, names);
1068
+ const roundup = LIST_NAME.test(item.full_name.split("/")[1]) || LIST_DESCRIPTION.test(item.description ?? "");
1069
+ const score = 2 * sharedSpecific.length + .5 * (shared.length - sharedSpecific.length) + 3 * wordOverlap + 1 * (hits - 1) + (comparesItself ? 1.5 : 0) + (source.language && item.language === source.language ? .5 : 0) + 2 * (Math.log10(item.stargazers_count + 1) / Math.log10(maxStars + 1)) - (days > 730 ? 1 : days > 365 ? .4 : 0);
1070
+ return {
1071
+ full_name: item.full_name,
1072
+ url: item.html_url,
1073
+ description: item.description,
1074
+ language: item.language,
1075
+ stars: item.stargazers_count,
1076
+ pushed_at: item.pushed_at,
1077
+ shared_topics: [...sharedSpecific, ...shared.filter((t) => !specific.has(t))],
1078
+ score: Math.round(score * 100) / 100,
1079
+ related: !addOn && !roundup && (shared.some((t) => !BROAD_TOPICS.has(t)) || wordOverlap > 0)
1080
+ };
1081
+ }).filter((r) => r.related).sort((a, b) => b.score - a.score);
1082
+ const cutoff = Math.max(MIN_SCORE, (related[0]?.score ?? 0) * .55);
1083
+ return related.filter((r) => r.score >= cutoff).slice(0, RESULT_LIMIT).map(({ related: _, ...repo }) => repo);
1084
+ }
1085
+ async function findSimilar(source, search, now = Date.now()) {
1086
+ const queries = buildQueries(source);
1087
+ const results = [];
1088
+ for (const { kind, q, sort } of queries) results.push({
1089
+ kind,
1090
+ items: await search(q, sort)
1091
+ });
1092
+ return rankSimilar(source, results, now);
1093
+ }
671
1094
  //#endregion
672
1095
  //#region server/github.ts
673
1096
  var DEFAULT_API_URL = "https://api.github.com";
@@ -702,6 +1125,12 @@ function createGitHubClient(token, apiUrl = process.env.GITHUB_API_URL ?? DEFAUL
702
1125
  if (json.errors?.length) throw new GitHubError(502, json.errors[0].message);
703
1126
  return json.data;
704
1127
  },
1128
+ get(path, accept = "application/vnd.github+json") {
1129
+ return request(`${apiUrl}${path}`, { headers: {
1130
+ ...headers,
1131
+ Accept: accept
1132
+ } });
1133
+ },
705
1134
  async rest(method, path) {
706
1135
  const response = await request(`${apiUrl}${path}`, {
707
1136
  method,
@@ -844,6 +1273,42 @@ async function addStar(client, repoNodeId) {
844
1273
  async function unstar(client, owner, name) {
845
1274
  await client.rest("DELETE", `/user/starred/${encodeURIComponent(owner)}/${encodeURIComponent(name)}`);
846
1275
  }
1276
+ async function tokenInfo(client) {
1277
+ const response = await client.get("/user");
1278
+ const json = await response.json().catch(() => ({}));
1279
+ if (!response.ok) throw new GitHubError(response.status, json.message ?? `GitHub returned ${response.status}.`);
1280
+ const header = response.headers.get("x-oauth-scopes");
1281
+ return {
1282
+ login: json.login ?? "",
1283
+ scopes: header === null ? null : header.split(",").map((s) => s.trim()).filter(Boolean)
1284
+ };
1285
+ }
1286
+ var SEARCH_PAGE_SIZE = 30;
1287
+ async function searchRepositories(client, q, sort) {
1288
+ const params = new URLSearchParams({
1289
+ q,
1290
+ per_page: String(SEARCH_PAGE_SIZE)
1291
+ });
1292
+ if (sort === "stars") params.set("sort", "stars");
1293
+ const response = await client.get(`/search/repositories?${params}`);
1294
+ const json = await response.json().catch(() => ({}));
1295
+ if (response.status === 403 || response.status === 429) throw new GitHubError(429, "GitHub allows 30 searches a minute. Try again in a minute.");
1296
+ if (!response.ok) throw new GitHubError(response.status, json.message ?? `GitHub returned ${response.status}.`);
1297
+ return json.items ?? [];
1298
+ }
1299
+ /** The README's opening prose, or null when the repo has none. */
1300
+ async function readmeOpening(client, fullName) {
1301
+ const response = await client.get(`/repos/${fullName}/readme`, "application/vnd.github.raw");
1302
+ if (!response.ok) return null;
1303
+ return readmeLead(await response.text());
1304
+ }
1305
+ async function similarTo(client, source) {
1306
+ const readme = await readmeOpening(client, source.full_name);
1307
+ return findSimilar({
1308
+ ...source,
1309
+ readme
1310
+ }, (q, sort) => searchRepositories(client, q, sort));
1311
+ }
847
1312
  //#endregion
848
1313
  //#region src/lib/local-api.ts
849
1314
  var LOCAL_APP_SIGNATURE = "github-stars-organizer";
@@ -6917,6 +7382,15 @@ function createLocalServer({ github, appDir, port, store, login }) {
6917
7382
  await unstar(github, owner, name);
6918
7383
  return c.json({});
6919
7384
  });
7385
+ api.get("/token", async (c) => c.json({
7386
+ connected: true,
7387
+ ...await tokenInfo(github)
7388
+ }));
7389
+ api.post("/similar", async (c) => {
7390
+ const { repo } = await c.req.json();
7391
+ if (!repo?.full_name) return c.json({ error: "Which repo?" }, 400);
7392
+ return c.json({ similar: await similarTo(github, repo) });
7393
+ });
6920
7394
  api.get("/backups", async (c) => c.json({
6921
7395
  directory: store.directory,
6922
7396
  backups: await store.list()
@@ -6992,7 +7466,7 @@ async function launch({ github, login, home, appDir, port }) {
6992
7466
  //#region cli/src/cli.ts
6993
7467
  var DEFAULT_PORT = 5185;
6994
7468
  var EXIT_FAILURE = 1;
6995
- var NOTICE = `Stars Organizer v1.2.0 Copyright (C) 2026 Armanc Keser
7469
+ var NOTICE = `Stars Organizer v1.3.0 Copyright (C) 2026 Armanc Keser
6996
7470
  Free software under the GNU AGPL v3 or later, with ABSOLUTELY NO WARRANTY.
6997
7471
  Source, license and bundled licenses: https://github.com/armanckeser/github-stars-organizer
6998
7472
  Not affiliated with or endorsed by GitHub.`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-stars-organizer",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Search, tag, rate and sort your GitHub stars into Lists, using your gh login. Runs locally; nothing to host.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "author": "Armanc Keser",
@@ -1 +0,0 @@
1
- import{R as e,a as t,m as n,n as r,r as i}from"./button-C0MQwO-R.js";var a=e(`external-link`,[[`path`,{d:`M15 3h6v6`,key:`1q9fwt`}],[`path`,{d:`M10 14 21 3`,key:`gplh6r`}],[`path`,{d:`M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6`,key:`a6xqqp`}]]);function o(e){return t(e.defaultTagName??`div`,e,e)}var s=i(`group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!`,{variants:{variant:{default:`bg-primary text-primary-foreground [a]:hover:bg-primary/80`,secondary:`bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80`,destructive:`bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20`,outline:`border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground`,ghost:`hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50`,link:`text-primary underline-offset-4 hover:underline`}},defaultVariants:{variant:`default`}});function c({className:e,variant:t=`default`,render:i,...a}){return o({defaultTagName:`span`,props:n({className:r(s({variant:t}),e)},a),render:i,state:{slot:`badge`,variant:t}})}export{a as n,c as t};