Use separate Svelte components
This commit is contained in:
		
							parent
							
								
									6656240361
								
							
						
					
					
						commit
						06a383227a
					
				
							
								
								
									
										132
									
								
								src/App.svelte
								
								
								
								
							
							
						
						
									
										132
									
								
								src/App.svelte
								
								
								
								
							| 
						 | 
				
			
			@ -1,12 +1,11 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
  import logo from "./assets/logo.svg";
 | 
			
		||||
  import Navbar from "./lib/Navbar.svelte";
 | 
			
		||||
  import Sidebar from "./lib/Sidebar.svelte";
 | 
			
		||||
  import Home from "./lib/Home.svelte";
 | 
			
		||||
  import Chat from "./lib/Chat.svelte";
 | 
			
		||||
  import {
 | 
			
		||||
    addChat,
 | 
			
		||||
    apiKeyStorage,
 | 
			
		||||
    chatsStorage,
 | 
			
		||||
    clearChats,
 | 
			
		||||
  } from "./lib/Storage.svelte";
 | 
			
		||||
  import Footer from "./lib/Footer.svelte";
 | 
			
		||||
 | 
			
		||||
  import { apiKeyStorage, chatsStorage } from "./lib/Storage.svelte";
 | 
			
		||||
 | 
			
		||||
  $: sortedChats = $chatsStorage.sort((a, b) => b.id - a.id);
 | 
			
		||||
  $: apiKey = $apiKeyStorage;
 | 
			
		||||
| 
						 | 
				
			
			@ -14,132 +13,23 @@
 | 
			
		|||
  let activeChatId: number;
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<nav class="navbar" aria-label="main navigation">
 | 
			
		||||
  <div class="navbar-brand">
 | 
			
		||||
    <a class="navbar-item" href="/">
 | 
			
		||||
      <img src={logo} alt="ChatGPT-web" width="28" height="28" />
 | 
			
		||||
      <p class="ml-2 is-size-4 has-text-weight-bold">ChatGPT-web</p>
 | 
			
		||||
    </a>
 | 
			
		||||
  </div>
 | 
			
		||||
</nav>
 | 
			
		||||
<Navbar />
 | 
			
		||||
 | 
			
		||||
<!-- svelte-ignore a11y-missing-attribute a11y-click-events-have-key-events -->
 | 
			
		||||
<section class="section">
 | 
			
		||||
  <div class="container is-fluid">
 | 
			
		||||
    <div class="columns">
 | 
			
		||||
      <div class="column is-one-fifth">
 | 
			
		||||
        <article class="panel is-link">
 | 
			
		||||
          <p class="panel-heading">Chats</p>
 | 
			
		||||
          {#if sortedChats.length === 0}
 | 
			
		||||
            <a class="panel-block">No chats...</a>
 | 
			
		||||
          {:else}
 | 
			
		||||
            {#each sortedChats as chat}
 | 
			
		||||
              <a
 | 
			
		||||
                class="panel-block {!apiKey ? 'is-disabled' : ''}"
 | 
			
		||||
                on:click={() => (activeChatId = chat.id)}>Chat {chat.id}</a
 | 
			
		||||
              >
 | 
			
		||||
            {/each}
 | 
			
		||||
          {/if}
 | 
			
		||||
        </article>
 | 
			
		||||
        <article class="panel is-link">
 | 
			
		||||
          <a
 | 
			
		||||
            class="panel-block {!apiKey ? 'is-disabled' : ''}"
 | 
			
		||||
            on:click={() => {
 | 
			
		||||
              activeChatId = addChat();
 | 
			
		||||
            }}>➕ New chat</a
 | 
			
		||||
          >
 | 
			
		||||
          <a
 | 
			
		||||
            class="panel-block {!apiKey ? 'is-disabled' : ''}"
 | 
			
		||||
            on:click={() => {
 | 
			
		||||
              clearChats();
 | 
			
		||||
              activeChatId = null;
 | 
			
		||||
            }}>🗑️ Clear chats</a
 | 
			
		||||
          >
 | 
			
		||||
 | 
			
		||||
          <a
 | 
			
		||||
            class="panel-block {!apiKey ? 'is-disabled' : ''}"
 | 
			
		||||
            on:click={() => {
 | 
			
		||||
              activeChatId = null;
 | 
			
		||||
            }}>🔙 Back to home</a
 | 
			
		||||
          >
 | 
			
		||||
        </article>
 | 
			
		||||
        <Sidebar bind:apiKey bind:sortedChats bind:activeChatId />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="column">
 | 
			
		||||
        {#if activeChatId}
 | 
			
		||||
          <Chat chatId={activeChatId} />
 | 
			
		||||
          <Chat bind:chatId={activeChatId} />
 | 
			
		||||
        {:else}
 | 
			
		||||
          <article class="message">
 | 
			
		||||
            <div class="message-body">
 | 
			
		||||
              <strong
 | 
			
		||||
                ><a href="https://github.com/Niek/chatgpt-web">ChatGPT-web</a
 | 
			
		||||
                ></strong
 | 
			
		||||
              >
 | 
			
		||||
              is a simple one-page web interface to the OpenAI ChatGPT API. To use
 | 
			
		||||
              it, you need to register for
 | 
			
		||||
              <a
 | 
			
		||||
                href="https://platform.openai.com/account/api-key"
 | 
			
		||||
                target="_blank"
 | 
			
		||||
                rel="noreferrer">an OpenAI API key</a
 | 
			
		||||
              >
 | 
			
		||||
              first. All messages are stored in your browser's local storage, so
 | 
			
		||||
              everything is <strong>private</strong>. You can also close the
 | 
			
		||||
              browser tab and come back later to continue the conversation.
 | 
			
		||||
            </div>
 | 
			
		||||
          </article>
 | 
			
		||||
          <article class="message {!apiKey ? 'is-danger' : 'is-warning'}">
 | 
			
		||||
            <div class="message-body">
 | 
			
		||||
              Set your OpenAI API key below:
 | 
			
		||||
 | 
			
		||||
              <form
 | 
			
		||||
                class="field has-addons has-addons-right"
 | 
			
		||||
                on:submit|preventDefault={(event) => {
 | 
			
		||||
                  apiKeyStorage.set(event.target[0].value);
 | 
			
		||||
                }}
 | 
			
		||||
              >
 | 
			
		||||
                <p class="control is-expanded">
 | 
			
		||||
                  <input
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    class="input {!apiKey ? 'is-danger' : ''}"
 | 
			
		||||
                    value={apiKey}
 | 
			
		||||
                  />
 | 
			
		||||
                </p>
 | 
			
		||||
                <p class="control">
 | 
			
		||||
                  <button class="button is-info" type="submit">Save</button>
 | 
			
		||||
                </p>
 | 
			
		||||
              </form>
 | 
			
		||||
 | 
			
		||||
              {#if !apiKey}
 | 
			
		||||
                <p class="help is-danger">
 | 
			
		||||
                  Please enter your OpenAI API key above to use ChatGPT-web
 | 
			
		||||
                </p>
 | 
			
		||||
              {/if}
 | 
			
		||||
            </div>
 | 
			
		||||
          </article>
 | 
			
		||||
          <article class="message is-info">
 | 
			
		||||
            <div class="message-body">
 | 
			
		||||
              Select an existing chat on the sidebar, or <a
 | 
			
		||||
                class={!apiKey ? "is-disabled" : ""}
 | 
			
		||||
                on:click={() => {
 | 
			
		||||
                  activeChatId = addChat();
 | 
			
		||||
                }}>create a new chat</a
 | 
			
		||||
              >
 | 
			
		||||
            </div>
 | 
			
		||||
          </article>
 | 
			
		||||
          <Home bind:activeChatId />
 | 
			
		||||
        {/if}
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</section>
 | 
			
		||||
 | 
			
		||||
<footer class="footer">
 | 
			
		||||
  <div class="content has-text-centered">
 | 
			
		||||
    <p>
 | 
			
		||||
      <strong>ChatGPT-web</strong>
 | 
			
		||||
      by
 | 
			
		||||
      <a href="https://niekvandermaas.nl/">Niek van der Maas</a>
 | 
			
		||||
      — see
 | 
			
		||||
      <a href="https://github.com/Niek/chatgpt-web">GitHub</a>
 | 
			
		||||
      for source code.
 | 
			
		||||
    </p>
 | 
			
		||||
  </div>
 | 
			
		||||
</footer>
 | 
			
		||||
<Footer />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -112,10 +112,10 @@
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<button
 | 
			
		||||
  class="button is-danger is-pulled-right"
 | 
			
		||||
  class="button is-warning is-pulled-right"
 | 
			
		||||
  on:click={() => {
 | 
			
		||||
    clearMessages(chatId);
 | 
			
		||||
  }}>Clear messages</button
 | 
			
		||||
  }}>🗑️ Clear messages</button
 | 
			
		||||
>
 | 
			
		||||
 | 
			
		||||
<p class="subtitle">Chat {chatId}</p>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
<footer class="footer">
 | 
			
		||||
  <div class="content has-text-centered">
 | 
			
		||||
    <p>
 | 
			
		||||
      <strong>ChatGPT-web</strong>
 | 
			
		||||
      by
 | 
			
		||||
      <a href="https://niekvandermaas.nl/">Niek van der Maas</a>
 | 
			
		||||
      — see
 | 
			
		||||
      <a href="https://github.com/Niek/chatgpt-web">GitHub</a>
 | 
			
		||||
      for source code.
 | 
			
		||||
    </p>
 | 
			
		||||
  </div>
 | 
			
		||||
</footer>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,66 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
  import { addChat, apiKeyStorage } from "./Storage.svelte";
 | 
			
		||||
 | 
			
		||||
  $: apiKey = $apiKeyStorage;
 | 
			
		||||
 | 
			
		||||
  export let activeChatId: number;
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<article class="message">
 | 
			
		||||
  <div class="message-body">
 | 
			
		||||
    <strong
 | 
			
		||||
      ><a href="https://github.com/Niek/chatgpt-web">ChatGPT-web</a></strong
 | 
			
		||||
    >
 | 
			
		||||
    is a simple one-page web interface to the OpenAI ChatGPT API. To use it, you
 | 
			
		||||
    need to register for
 | 
			
		||||
    <a
 | 
			
		||||
      href="https://platform.openai.com/account/api-key"
 | 
			
		||||
      target="_blank"
 | 
			
		||||
      rel="noreferrer">an OpenAI API key</a
 | 
			
		||||
    >
 | 
			
		||||
    first. All messages are stored in your browser's local storage, so everything
 | 
			
		||||
    is <strong>private</strong>. You can also close the browser tab and come
 | 
			
		||||
    back later to continue the conversation.
 | 
			
		||||
  </div>
 | 
			
		||||
</article>
 | 
			
		||||
<article class="message {!apiKey ? 'is-danger' : 'is-warning'}">
 | 
			
		||||
  <div class="message-body">
 | 
			
		||||
    Set your OpenAI API key below:
 | 
			
		||||
 | 
			
		||||
    <form
 | 
			
		||||
      class="field has-addons has-addons-right"
 | 
			
		||||
      on:submit|preventDefault={(event) => {
 | 
			
		||||
        apiKeyStorage.set(event.target[0].value);
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <p class="control is-expanded">
 | 
			
		||||
        <input
 | 
			
		||||
          type="text"
 | 
			
		||||
          class="input {!apiKey ? 'is-danger' : ''}"
 | 
			
		||||
          value={apiKey}
 | 
			
		||||
        />
 | 
			
		||||
      </p>
 | 
			
		||||
      <p class="control">
 | 
			
		||||
        <button class="button is-info" type="submit">Save</button>
 | 
			
		||||
      </p>
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
    {#if !apiKey}
 | 
			
		||||
      <p class="help is-danger">
 | 
			
		||||
        Please enter your OpenAI API key above to use ChatGPT-web
 | 
			
		||||
      </p>
 | 
			
		||||
    {/if}
 | 
			
		||||
  </div>
 | 
			
		||||
</article>
 | 
			
		||||
<article class="message is-info">
 | 
			
		||||
  <div class="message-body">
 | 
			
		||||
    <!-- svelte-ignore a11y-missing-attribute a11y-click-events-have-key-events -->
 | 
			
		||||
    Select an existing chat on the sidebar, or
 | 
			
		||||
    <a
 | 
			
		||||
      class={!apiKey ? "is-disabled" : ""}
 | 
			
		||||
      on:click={() => {
 | 
			
		||||
        activeChatId = addChat();
 | 
			
		||||
      }}>create a new chat</a
 | 
			
		||||
    >
 | 
			
		||||
  </div>
 | 
			
		||||
</article>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
  import logo from "../assets/logo.svg";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<nav class="navbar" aria-label="main navigation">
 | 
			
		||||
  <div class="navbar-brand">
 | 
			
		||||
    <a class="navbar-item" href="/">
 | 
			
		||||
      <img src={logo} alt="ChatGPT-web" width="28" height="28" />
 | 
			
		||||
      <p class="ml-2 is-size-4 has-text-weight-bold">ChatGPT-web</p>
 | 
			
		||||
    </a>
 | 
			
		||||
  </div>
 | 
			
		||||
</nav>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
  import { addChat, clearChats } from "./Storage.svelte";
 | 
			
		||||
  import type { Chat } from "./Types.svelte";
 | 
			
		||||
 | 
			
		||||
  export let activeChatId: number;
 | 
			
		||||
  export let sortedChats: Chat[];
 | 
			
		||||
  export let apiKey: string;
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<!-- svelte-ignore a11y-missing-attribute a11y-click-events-have-key-events -->
 | 
			
		||||
<aside class="menu">
 | 
			
		||||
  <p class="menu-label">Chats</p>
 | 
			
		||||
  <ul class="menu-list">
 | 
			
		||||
    {#if sortedChats.length === 0}
 | 
			
		||||
      <a class="panel-block">No chats...</a>
 | 
			
		||||
    {:else}
 | 
			
		||||
      <li>
 | 
			
		||||
        <ul>
 | 
			
		||||
          {#each sortedChats as chat}
 | 
			
		||||
            <li>
 | 
			
		||||
              <a
 | 
			
		||||
                class="panel-block {!apiKey
 | 
			
		||||
                  ? 'is-disabled'
 | 
			
		||||
                  : ''} {activeChatId === chat.id
 | 
			
		||||
                  ? 'has-background-light'
 | 
			
		||||
                  : ''}"
 | 
			
		||||
                on:click={() => (activeChatId = chat.id)}>Chat {chat.id}</a
 | 
			
		||||
              >
 | 
			
		||||
            </li>
 | 
			
		||||
          {/each}
 | 
			
		||||
        </ul>
 | 
			
		||||
      </li>
 | 
			
		||||
    {/if}
 | 
			
		||||
  </ul>
 | 
			
		||||
  <p class="menu-label">Actions</p>
 | 
			
		||||
  <ul class="menu-list">
 | 
			
		||||
    <li>
 | 
			
		||||
      <a
 | 
			
		||||
        class="panel-block {!apiKey ? 'is-disabled' : ''}"
 | 
			
		||||
        on:click={() => {
 | 
			
		||||
          activeChatId = addChat();
 | 
			
		||||
        }}>➕ New chat</a
 | 
			
		||||
      >
 | 
			
		||||
    </li>
 | 
			
		||||
    <li>
 | 
			
		||||
      <a
 | 
			
		||||
        class="panel-block {!apiKey ? 'is-disabled' : ''}"
 | 
			
		||||
        on:click={() => {
 | 
			
		||||
          clearChats();
 | 
			
		||||
          activeChatId = null;
 | 
			
		||||
        }}>🗑️ Clear chats</a
 | 
			
		||||
      >
 | 
			
		||||
    </li>
 | 
			
		||||
    <li>
 | 
			
		||||
      <a
 | 
			
		||||
        class="panel-block {!apiKey ? 'is-disabled' : ''}"
 | 
			
		||||
        on:click={() => {
 | 
			
		||||
          activeChatId = null;
 | 
			
		||||
        }}>🔙 Back to home</a
 | 
			
		||||
      >
 | 
			
		||||
    </li>
 | 
			
		||||
  </ul>
 | 
			
		||||
</aside>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
import "./app.scss";
 | 
			
		||||
import App from "./App.svelte";
 | 
			
		||||
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
const app = new App({
 | 
			
		||||
  target: document.getElementById("app"),
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue