Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Show pinned orgs on the front page
Alexis Sellier committed 4 years ago
commit e2cc61671b6887609db5717f7080baf1cd859232
parent 8493dfe52cf2d62b375d1ce1155447ae30323e75
8 files changed +89 -23
modified src/Header.svelte
@@ -34,6 +34,22 @@
    display: flex;
    align-items: center;
  }
+
  header .nav {
+
    display: inline-block;
+
    height: 100%;
+
    margin-left: 1.5rem;
+
    white-space: nowrap;
+
  }
+
  header .nav a {
+
    display: inline-block;
+
    padding: 0.5rem 0.5rem;
+
    margin-right: 1.5rem;
+
    font-weight: 500;
+
    color: var(--color-foreground-6);
+
  }
+
  header .nav a:hover {
+
    color: var(--color-foreground);
+
  }
  .logo {
    display: flex;
  }
@@ -54,7 +70,7 @@
  .search {
    height: 42px;
    width: 16rem;
-
    margin-left: 1rem;
+
    margin-left: 1.5rem;
    display: inline-block;
  }
  .address {
@@ -122,6 +138,10 @@
    <div class="search">
      <Search />
    </div>
+
    <div class="nav">
+
      <a use:link href="/orgs/">Orgs</a>
+
      <a use:link href="/registrations">Register</a>
+
    </div>
  </div>

  <div class="right">
modified src/base/home/Index.svelte
@@ -17,6 +17,6 @@

<main>
  <div>
-
    <Orgs {config} />
+
    <Orgs {config} pinned />
  </div>
</main>
modified src/base/orgs/Index.svelte
@@ -9,7 +9,11 @@
  import List from './List.svelte';

  export let config: Config;
+
  export let pinned = false;

+
  const getOrgs = pinned && (config.orgs.pinned.length > 0)
+
    ? Org.getMulti(config.orgs.pinned, config)
+
    : Org.getAll(config);
  const onCreate = () => modal = Create;
  let modal: typeof SvelteComponent | null = null;

@@ -32,14 +36,14 @@
  }

  .padding {
-
    padding: 0 3rem 3rem 3rem;
+
    padding: 0 2rem 2rem 2rem;
  }

  .my-orgs {
-
    margin-bottom: 3rem;
+
    margin-bottom: 2rem;
  }
  .orgs-empty {
-
    margin-left: 3rem;
+
    margin-left: 2rem;
    padding: 1rem 0 2rem 0;
    font-style: italic;
    color: var(--color-foreground-faded);
@@ -50,7 +54,7 @@
  }

  .loading {
-
    padding: 3rem 0;
+
    padding: 2rem 0;
  }
</style>

@@ -90,7 +94,7 @@
    <span><strong>Orgs</strong> of the Radicle network</span>
  </header>

-
  {#await Org.getAll(config)}
+
  {#await getOrgs}
    <div class="loading">
      <Loading center />
    </div>
modified src/base/orgs/List.svelte
@@ -1,4 +1,6 @@
<script lang="ts">
+
  import { ethers } from 'ethers';
+
  import { onMount } from 'svelte';
  import { Link } from 'svelte-routing';
  import type { Org } from '@app/base/orgs/Org';
  import Avatar from '@app/Avatar.svelte';
@@ -10,32 +12,43 @@
  export let config: Config;
  export let orgs: Org[];

-
  const orgsAddresses = orgs.map(org => org.address);
+
  const orgMembers: Record<string, string[]> = {};
+
  const getProfiles = Profile.getMulti(orgs.map(o => o.name ?? o.address), config);
+

+
  onMount(async () => {
+
    const promises = orgs.map(org => org.getMembers(config).then(members => {
+
      orgMembers[ethers.utils.getAddress(org.address)] = members;
+
    }));
+

+
    Promise.all(promises);
+
  });
</script>

<style>
  .org {
-
    width: 8rem;
-
    height: 8rem;
+
    width: 10rem;
+
    height: 10rem;
    margin-left: 3rem;
    margin-top: 1.5rem;
    margin-bottom: 1.5rem;
+
    padding: 1rem;
    display: inline-block;
    text-align: center;
+
    border-radius: 1rem;
  }
-
  .org:hover .org-label {
-
    color: var(--color-background);
-
    background: var(--color-secondary);
+
  .org:hover  {
+
    background: var(--color-foreground-background-lighter);
  }
  .org-avatar {
    margin: 0 auto;
    text-align: center;
-
    width: 3rem;
-
    height: 3rem;
+
    width: 4rem;
+
    height: 4rem;
  }
  .org-label {
    color: var(--color-foreground-90);
    display: inline-block;
+
    font-weight: var(--font-weight-medium);
    margin-top: 0.75rem;
    border-radius: 0.75rem;
    padding: 0rem 0.5rem;
@@ -43,6 +56,10 @@
    overflow-x: hidden;
    max-width: 8rem;
  }
+
  .org-members {
+
    font-size: 0.875rem;
+
    color: var(--color-foreground-faded);
+
  }
  .list {
    display: flex;
    flex-direction: row;
@@ -53,15 +70,15 @@
  }
</style>

-
{#await Profile.getMulti(orgsAddresses, config)}
+
{#await getProfiles}
  <div class="loading">
    <Loading center />
  </div>
{:then profiles}
  <div class="list">
    {#each profiles as profile}
-
      <div class="org">
-
        <Link to={`/orgs/${profile.nameOrAddress}`}>
+
      <Link to={`/orgs/${profile.nameOrAddress}`}>
+
        <div class="org">
          <div class="org-avatar">
            <Avatar source={profile.avatar ?? profile.address} />
          </div>
@@ -72,8 +89,15 @@
              {formatAddress(profile.address)}
            {/if}
          </div>
-
        </Link>
-
      </div>
+
          <div class="org-members">
+
            {#if orgMembers[profile.address]?.length}
+
              {orgMembers[profile.address].length} members
+
            {:else}
+
              {formatAddress(profile.address)}
+
            {/if}
+
          </div>
+
        </div>
+
      </Link>
    {:else}
      <slot />
    {/each}
modified src/base/orgs/Org.ts
@@ -172,6 +172,13 @@ export class Org {
    }
  }

+
  static async getMulti(ids: string[], config: Config): Promise<Array<Org>> {
+
    const results = await Promise.all(ids.map(addr => Org.get(addr, config)));
+
    const orgs = results.filter((org): org is Org => org != null);
+

+
    return orgs;
+
  }
+

  static async getAll(config: Config): Promise<Array<Org>> {
    const result = await utils.querySubgraph(config.orgs.subgraph, GetOrgs, {});
    const orgs: Org[] = [];
modified src/config.json
@@ -12,7 +12,14 @@
    },
    "orgs": {
      "subgraph": "https://gateway.thegraph.com/api/1758a78ae257ad4906f9c638e4a68c19/subgraphs/id/0x2f0963e77ca6ac0c2dad1bf4147b6b40e0dd8728-0",
-
      "contractHash": "0x5c34bb0755876de98e801805e6685456eea739ad0abba1cc450a7ee0f2a70b74"
+
      "contractHash": "0x5c34bb0755876de98e801805e6685456eea739ad0abba1cc450a7ee0f2a70b74",
+
      "pinned": [
+
        "alt-clients.radicle.eth",
+
        "community.radicle.eth",
+
        "upstream.radicle.eth",
+
        "gnosisguild.radicle.eth",
+
        "dxdao.radicle.eth"
+
      ]
    },
    "safe": {
      "api": "https://safe-transaction.gnosis.io",
@@ -37,7 +44,8 @@
    },
    "orgs": {
      "subgraph": "https://api.thegraph.com/subgraphs/name/radicle-dev/radicle-orgs-rinkeby",
-
      "contractHash": "0x5c34bb0755876de98e801805e6685456eea739ad0abba1cc450a7ee0f2a70b74"
+
      "contractHash": "0x5c34bb0755876de98e801805e6685456eea739ad0abba1cc450a7ee0f2a70b74",
+
      "pinned": []
    },
    "safe": {
      "api": "https://safe-transaction.rinkeby.gnosis.io",
modified src/config.ts
@@ -31,7 +31,7 @@ export class Config {
  radToken: { address: string };
  orgFactory: { address: string };
  reverseRegistrar: { address: string };
-
  orgs: { subgraph: string; contractHash: string };
+
  orgs: { subgraph: string; contractHash: string; pinned: string[] };
  gasLimits: { createOrg: number };
  provider: ethers.providers.JsonRpcProvider;
  signer: ethers.Signer & TypedDataSigner | WalletConnectSigner | null;
modified src/utils.ts
@@ -264,6 +264,9 @@ export async function resolveEnsProfile(addressOrName: string, profileType: Prof

  if (name) {
    const resolver = await config.provider.getResolver(name);
+
    if (! resolver) {
+
      return null;
+
    }

    if (profileType === ProfileType.Full) {
      const registration = await getRegistration(name, config, resolver);