访问Git Hub

查看GitHub

适配设备:Pro

作者:rikka

下载量:28 · 点赞:1

可信源码风险提示:保存或下载前请阅读源码和权限声明。
SHA-256549e5091d9d17fedec30f6ad93dfbb234d2510662deb40180e5b71f59e9c52b0
const view = ui.signal('menu');
const title = ui.signal('');
const lines = ui.signal([]);

function req(url, parse) {
  title.set('用户');
  lines.set(['']);
  view.set('result');
  ui.refresh();
  system.http.request({
    url: url,
    header: { 'User-Agent': 'JSLab/1.0' },
    responseType: 'text',
    success: response => {
      try {
        const d = JSON.parse(response.data);
        if (d && d.message) {
          lines.set(['GitHub 返回:', d.message.slice(0, 72)]);
        } else {
          lines.set(parse(d));
        }
      } catch (e) {
        lines.set(['响应非 JSON:', response.data.slice(0, 80)]);
      }
      ui.refresh();
    },
    fail: (data, code) => {
      lines.set(['请求失败: ' + code, String(data)]);
      ui.refresh();
    }
  });
}

async function ask(cfg) {
  const res = await dialog.text({
    title: cfg.title,
    message: cfg.message,
    placeholder: cfg.placeholder,
    maxLength: 60
  });
  if (res.action !== 'confirm') return;
  const q = res.value.trim();
  if (!q) return;
  title.set(cfg.resultTitle + ' · ' + q);
  req(cfg.url(q), cfg.parse);
}

async function queryUser() {
  const res = await dialog.text({
    title: '查询用户',
    message: '输入 GitHub 用户名',
    placeholder: '如 octocat',
    maxLength: 40
  });
  if (res.action !== 'confirm') return;
  const q = res.value.trim();
  if (!q) return;
  title.set('用户 · ' + q);
  req('https://api.github.com/users/' + encodeURIComponent(q), d => {
    return [
      '登录名: ' + d.login,
      '名字: ' + (d.name || '无'),
      '仓库: ' + d.public_repos,
      '粉丝: ' + d.followers + ' / 关注: ' + d.following,
      '位置: ' + (d.location || '未知'),
      '简介: ' + (d.bio || '无'),
      '注册: ' + String(d.created_at || '').slice(0, 10)
    ];
  });
}

async function queryRepo() {
  const res = await dialog.text({
    title: '查询仓库',
    message: '输入 owner/repo 格式',
    placeholder: '如 octocat/Hello-World',
    maxLength: 100
  });
  if (res.action !== 'confirm') return;
  const q = res.value.trim();
  if (!q) return;
  if (q.indexOf('/') < 0) {
    await dialog.alert({ title: '格式错误', message: '应为 owner/repo 格式' });
    return;
  }
  title.set('仓库 · ' + q);
  req('https://api.github.com/repos/' + encodeURIComponent(q), d => {
    return [
      '仓库: ' + d.full_name,
      '描述: ' + (d.description || '无'),
      '语言: ' + (d.language || '未知'),
      'Stars: ' + d.stargazers_count + ' / Forks: ' + d.forks_count,
      'Issues: ' + d.open_issues_count,
      '许可: ' + (d.license ? d.license.spdx_id : '无'),
      '更新: ' + String(d.updated_at || '').slice(0, 10)
    ];
  });
}

const SEARCH = {
  code: {
    title: '搜索代码',
    message: '输入代码关键词',
    placeholder: '如 accelerometer',
    resultTitle: '代码',
    url: q => 'https://api.github.com/search/code?q=' + encodeURIComponent(q) + '&per_page=5',
    parse: d => d.items.slice(0, 5).map(it => [it.name, it.repository.full_name]).flat()
  },
  repo: {
    title: '搜索仓库',
    message: '输入仓库关键词',
    placeholder: '如 watchface',
    resultTitle: '仓库',
    url: q => 'https://api.github.com/search/repositories?q=' + encodeURIComponent(q) + '&sort=stars&per_page=5',
    parse: d => d.items.slice(0, 5).map(r => [
      r.full_name + ' ★' + r.stargazers_count,
      (r.language || '未知') + ' · ' + String(r.description || '').slice(0, 36)
    ]).flat()
  },
  issue: {
    title: '搜索议题',
    message: '输入议题关键词',
    placeholder: '如 crash',
    resultTitle: '议题',
    url: q => 'https://api.github.com/search/issues?q=' + encodeURIComponent(q) + '&per_page=5',
    parse: d => d.items.slice(0, 5).map(i => [
      i.title.slice(0, 40),
      (i.state === 'open' ? '开' : '关') + ' · ' + String(i.repository_url || '').split('/').pop()
    ]).flat()
  },
  pr: {
    title: '搜索拉取请求',
    message: '输入 PR 关键词',
    placeholder: '如 fix crash',
    resultTitle: 'PR',
    url: q => 'https://api.github.com/search/issues?q=' + encodeURIComponent(q) + '+type:pr&per_page=5',
    parse: d => d.items.slice(0, 5).map(p => [
      '#' + p.number + ' ' + p.title.slice(0, 34),
      (p.state === 'open' ? '开' : '关') + ' · ' + String(p.repository_url || '').split('/').pop()
    ]).flat()
  },
  org: {
    title: '搜索组织',
    message: '输入组织名',
    placeholder: '如 openharmony',
    resultTitle: '组织',
    url: q => 'https://api.github.com/search/users?q=' + encodeURIComponent(q) + '+type:org&per_page=5',
    parse: d => d.items.slice(0, 5).map(o => [
      o.login,
      String(o.description || '无简介').slice(0, 40)
    ]).flat()
  }
};

function back() {
  view.set('menu');
  ui.refresh();
}

ui.setTitle('GitHub 查询工具');
ui.render(() => {
  if (view.get() === 'result') {
    return [
      ui.button('← 返回', back, { id: 'b', tone: 'neutral', height: 40 }),
      ui.spacer(8),
      ui.heading(title.get(), { align: 'center' }),
      ui.spacer(6)
    ].concat(lines.get().map((l, i) => ui.text(l, {
      size: 13, color: i === 0 ? '#ffd75e' : (i % 2 === 1 ? '#bbbbbb' : '#ffffff'),
      align: 'center', lines: 1, bold: i === 0
    })));
  }
  return [
    ui.heading('GitHub 查询', { align: 'center' }),
    ui.row([
      ui.button('查询用户', queryUser, { id: 'u', flex: 1, tone: 'primary', height: 52 }),
      ui.button('查询仓库', queryRepo, { id: 'r', flex: 1, tone: 'success', height: 52 })
    ], { gap: 8 }),
    ui.spacer(14),
    ui.divider({ color: '#333333' }),
    ui.spacer(10),
    ui.text('搜索', { heading: true, align: 'center' }),
    ui.row([
      ui.button('代码', () => ask(SEARCH.code), { id: 'c', flex: 1, tone: 'warning', height: 46 }),
      ui.button('仓库', () => ask(SEARCH.repo), { id: 'r2', flex: 1, tone: 'primary', height: 46 })
    ], { gap: 8 }),
    ui.spacer(6),
    ui.row([
      ui.button('议题', () => ask(SEARCH.issue), { id: 'i', flex: 1, tone: 'success', height: 46 }),
      ui.button('拉取请求', () => ask(SEARCH.pr), { id: 'p', flex: 1, tone: 'danger', height: 46 })
    ], { gap: 8 }),
    ui.spacer(6),
    ui.row([
      ui.button('组织', () => ask(SEARCH.org), { id: 'o', flex: 1, tone: 'neutral', height: 46 })
    ], { gap: 8 })
  ];
});