Assets: Display extension author in the list (#4551) * Assets: Display extension author in the list * Fix overflow of long text

45a7c6b2aacae8d6c675c2e4999d34757df13af4

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
2 files changed, +64 -5Ignore whitespace
public/scripts/extensions/assets/index.js+37 -3
@@ -10,7 +10,7 @@ import { POPUP_TYPE, Popup, callGenericPopup } from '../../popup.js';
10import { executeSlashCommandsWithOptions } from '../../slash-commands.js';10import { executeSlashCommandsWithOptions } from '../../slash-commands.js';
11import { accountStorage } from '../../util/AccountStorage.js';11import { accountStorage } from '../../util/AccountStorage.js';
12import { flashHighlight, getStringHash, isValidUrl } from '../../utils.js';12import { flashHighlight, getStringHash, isValidUrl } from '../../utils.js';
13import { t } from '../../i18n.js';13import { t, translate } from '../../i18n.js';
14export { MODULE_NAME };14export { MODULE_NAME };
1515
16const MODULE_NAME = 'assets';16const MODULE_NAME = 'assets';
@@ -60,6 +60,36 @@ const KNOWN_TYPES = {
60 'blip': t`Blip sounds`,60 'blip': t`Blip sounds`,
61};61};
6262
63const EMPTY_AUTHOR = {
64 name: '',
65 url: '',
66};
67
68/**
69 * Extracts the repository author from a given URL.
70 * @param {string} url - The URL of the repository.
71 * @returns {{name: string, url: string}} Object containing the author's name and URL, or empty strings if not found.
72 */
73function getAuthorFromUrl(url) {
74 const result = structuredClone(EMPTY_AUTHOR);
75
76 try {
77 const parsedUrl = new URL(url);
78 const pathSegments = parsedUrl.pathname.split('/').filter(s => s.length > 0);
79
80 // TODO: Handle non-GitHub URLs if needed
81 if (parsedUrl.host === 'github.com' && pathSegments.length >= 2) {
82 result.name = pathSegments[0];
83 result.url = `${parsedUrl.protocol}//${parsedUrl.hostname}/${result.name}`;
84 }
85 }
86 catch (error) {
87 console.debug(DEBUG_PREFIX, 'Error parsing URL:', error);
88 }
89
90 return result;
91}
92
63async function downloadAssetsList(url) {93async function downloadAssetsList(url) {
64 updateCurrentAssets().then(async function () {94 updateCurrentAssets().then(async function () {
65 fetch(url, { cache: 'no-cache' })95 fetch(url, { cache: 'no-cache' })
@@ -88,7 +118,8 @@ async function downloadAssetsList(url) {
88 $('#assets_type_select').append($('<option />', { value: '', text: t`All` }));118 $('#assets_type_select').append($('<option />', { value: '', text: t`All` }));
89119
90 for (const type of assetTypes) {120 for (const type of assetTypes) {
91 const option = $('<option />', { value: type, text: t([KNOWN_TYPES[type] || type]) });121 const text = translate(KNOWN_TYPES[type] || type);
122 const option = $('<option />', { value: type, text: text });
92 $('#assets_type_select').append(option);123 $('#assets_type_select').append(option);
93 }124 }
94125
@@ -184,10 +215,11 @@ async function downloadAssetsList(url) {
184 const title = assetType === 'extension' ? t`Extension repo/guide:` + ` ${url}` : t`Preview in browser`;215 const title = assetType === 'extension' ? t`Extension repo/guide:` + ` ${url}` : t`Preview in browser`;
185 const previewIcon = (assetType === 'extension' || assetType === 'character') ? 'fa-arrow-up-right-from-square' : 'fa-headphones-simple';216 const previewIcon = (assetType === 'extension' || assetType === 'character') ? 'fa-arrow-up-right-from-square' : 'fa-headphones-simple';
186 const toolTag = assetType === 'extension' && asset['tool'];217 const toolTag = assetType === 'extension' && asset['tool'];
218 const author = url && assetType === 'extension' ? getAuthorFromUrl(url) : EMPTY_AUTHOR;
187219
188 const assetBlock = $('<i></i>')220 const assetBlock = $('<i></i>')
189 .append(element)221 .append(element)
190 .append(`<div class="flex-container flexFlowColumn flexNoGap">222 .append(`<div class="flex-container flexFlowColumn flexNoGap wide100p overflowHidden">
191 <span class="asset-name flex-container alignitemscenter">223 <span class="asset-name flex-container alignitemscenter">
192 <b>${displayName}</b>224 <b>${displayName}</b>
193 <a class="asset_preview" href="${url}" target="_blank" title="${title}">225 <a class="asset_preview" href="${url}" target="_blank" title="${title}">
@@ -195,6 +227,8 @@ async function downloadAssetsList(url) {
195 </a>` +227 </a>` +
196 (toolTag ? '<span class="tag" title="' + t`Adds a function tool` + '"><i class="fa-solid fa-sm fa-wrench"></i> ' +228 (toolTag ? '<span class="tag" title="' + t`Adds a function tool` + '"><i class="fa-solid fa-sm fa-wrench"></i> ' +
197 t`Tool` + '</span>' : '') +229 t`Tool` + '</span>' : '') +
230 '<span class="expander"></span>' +
231 (author.name ? `<a href="${author.url}" target="_blank" class="asset-author-info"><i class="fa-solid fa-at fa-xs"></i><span>${author.name}</span></a>` : '') +
198 `</span>232 `</span>
199 <small class="asset-description">233 <small class="asset-description">
200 ${description}234 ${description}
public/scripts/extensions/assets/style.css+27 -2
@@ -35,14 +35,15 @@
35 color: inherit;35 color: inherit;
36}36}
3737
38.assets-list-div > i {38.assets-list-div>i {
39 display: flex;39 display: flex;
40 flex-direction: row;40 flex-direction: row;
41 align-items: center;41 align-items: center;
42 justify-content: left;42 justify-content: left;
43 padding: 5px;43 padding: 10px 5px;
44 font-style: normal;44 font-style: normal;
45 gap: 5px;45 gap: 5px;
46 border-bottom: 1px solid var(--SmartThemeBorderColor);
46}47}
4748
48.assets-list-div i span:first-of-type {49.assets-list-div i span:first-of-type {
@@ -173,3 +174,27 @@
173 opacity: 0.9;174 opacity: 0.9;
174 margin-left: 2px;175 margin-left: 2px;
175}176}
177
178.asset-name .asset-author-info {
179 display: flex;
180 align-items: baseline;
181 gap: 2px;
182 opacity: 0.7;
183 font-size: 0.85em;
184 overflow: hidden;
185}
186
187.asset-name .asset-author-info>span {
188 white-space: nowrap;
189 overflow: hidden;
190 text-overflow: ellipsis;
191}
192
193.asset-name .asset-author-info:hover {
194 opacity: 1;
195 transition: opacity var(--animation-duration) ease-in-out;
196}
197
198.asset-name>b {
199 font-weight: 600;
200}