pull/4/head^2
Nilesh 2022-05-23 18:17:44 +01:00
rodzic 941fccd782
commit 4dd1cfb63c
7 zmienionych plików z 177 dodań i 125 usunięć

Wyświetl plik

@ -12,10 +12,11 @@
import ItemDetail from "./ItemDetail.svelte"
import ItemList from "./ItemList.svelte"
import AdvancedSearch from "./AdvancedSearch.svelte"
import { SearchIcon } from "@rgossiaux/svelte-heroicons/outline";
import { SearchIcon, CogIcon, BookmarkAltIcon, BookmarkIcon } from "@rgossiaux/svelte-heroicons/outline";
let currentView = "/topics";
let randomItemId;
let alltopics = [];
function getRandomItemId(){
fetch('/learn.json?_shape=array&sql=select+rowid+from+items+order+by+random()+limit+1').then(r => r.json())
@ -24,6 +25,12 @@
});
}
$: fetch(`/learn/topics.json?_shape=array&_size=5000`)
.then(r => r.json())
.then(data => {
alltopics = data;
});
async function hashchange() {
// the poor man's router!
const path = window.location.hash.slice(1);
@ -45,14 +52,14 @@
<svelte:window on:hashchange={hashchange}/>
<TailwindUI.AppShell>
<TailwindUI.AppShell {alltopics}>
<svelte:fragment slot="content">
{#if currentView === "/home" || currentView === "/"}
<Home/>
{:else if currentView === "/game"}
<SkillTree/>
{:else if currentView === "/topics"}
<TopicList/>
<TopicList {alltopics}/>
{:else if currentView.startsWith("/topic/")}
<TopicDetail topicname={currentView.split("/").slice(2).join("/")}/>
{:else if currentView === "/formats"}
@ -93,17 +100,18 @@
</a>
<hr/>
<a href="#/wanttolearn" class={(currentView === "/wanttolearn" ? 'bg-indigo-800' : '') + " text-white w-full hover:bg-indigo-600 group flex items-center px-2 py-2 text-sm font-medium rounded-md"}>
<SearchIcon class="mr-4 flex-shrink-0 h-6 w-6 text-indigo-300"/>
<BookmarkIcon class="mr-4 flex-shrink-0 h-6 w-6 text-indigo-300"/>
Want to learn
</a>
<a href="#/finishedlearning" class={(currentView === "/finishedlearning" ? 'bg-indigo-800' : '') + " text-white w-full hover:bg-indigo-600 group flex items-center px-2 py-2 text-sm font-medium rounded-md"}>
<SearchIcon class="mr-4 flex-shrink-0 h-6 w-6 text-indigo-300"/>
<BookmarkAltIcon class="mr-4 flex-shrink-0 h-6 w-6 text-indigo-300"/>
Finished learning
</a>
<hr/>
<a href="/learn" class="text-indigo-100 hover:bg-indigo-600 w-full group flex items-center px-2 py-2 text-sm font-medium rounded-md">
<SearchIcon class="mr-4 flex-shrink-0 h-6 w-6 text-indigo-300"/>
<CogIcon class="mr-4 flex-shrink-0 h-6 w-6 text-indigo-300"/>
Datasette
</a>
</svelte:fragment>
</TailwindUI.AppShell>

Wyświetl plik

@ -1,90 +1,78 @@
<script>
import ZoomSvg from '@svelte-parts/zoom/svg'
import { fly } from 'svelte/transition';
let sidePanelShown = true;
let currentNode = null;
let nodes = [
{id: 1, name: "test", x: 100, y: 200, size: 50, color: "#ff3e00"},
{id: 2, name: "second", x: 400, y: 300, size: 30, color: "#ff3eff"}
]
let edges = [
{id: 1, from: nodes[0], to: nodes[1]}
]
function handleNodeMouseEnter(ev){
ev.target.style.fill = "#aa3e00"
}
function handleNodeMouseLeave(ev){
ev.target.style.fill = "#ff3e00"
}
function handleNodeClick(ev){
sidePanelShown = true;
currentNode = ev.target;
}
import { scale } from 'svelte/transition';
import { cubicIn } from 'svelte/easing';
let graph = {
name: "Top",
children: [
{name: "first", children: [
{name: "first -> A", children: [], color: "red-500"},
{name: "first -> B", children: [], color: "green-500"},
{name: "first -> c", children: [], color: "yellow-500"},
{name: "first -> d", children: [], color: "blue-500"},
], pos: [], size: 35, color: "green-300"},
{name: "second", children: [], pos: [], size: 35, color: "red-500"},
{name: "third", children: [], pos: [], size: 35, color: "yellow-500"},
{name: "fourth", children: [], pos: [], size: 35, color: "teal-400"},
]
}
let currentParent = null;
let currentChild = graph;
function findParent(child, tree){
if(graph == child) return null;
if(tree.children.indexOf(child) > -1) return tree;
// Will have to look at grandchildren
tree.children.forEach(c => {
let x = findParent(child, c);
if (x != -1) return c;
});
return -1;
}
function switchTo(parent, child){
[currentParent, currentChild] = [parent, child];
}
function siblings(parent, child){
if(!parent) return [];
return parent.children.filter(n => n != child)
}
</script>
<div class="flex flex-col">
<ZoomSvg viewBox="0 0 1200 900">
{#if currentParent}<div class="flex flex-row justify-center mb-4">
<span>
<button type="button" on:click="{ e => switchTo(findParent(currentParent, graph), currentParent) }" class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
{currentParent.name}
</button>
</span>
</div>{/if}
{#each edges as edge}
<line x1={edge.from.x} y1={edge.from.y} x2={edge.to.x} y2={edge.to.y} stroke="black" stroke-width="5" />
{/each}
{#each nodes as node}
<circle cx={node.x} cy={node.y} r={node.size} fill={node.color} on:mouseenter={handleNodeMouseEnter} on:mouseleave={handleNodeMouseLeave} on:click={handleNodeClick}/>
{/each}
<h2 class="text-3xl my-4 text-center font-extrabold tracking-tight sm:text-4xl">{currentChild.name}</h2>
<g>
<rect x="120" y="320" width="100" height="100" fill="none" stroke="black" rx="15" />
<text x="400" y="150" font-family="Verdana" font-size="85" fill="green" stroke="yellow">Hello</text>
</g>
</ZoomSvg>
<div class="flex flex-row justify-center my-4">
<span class="relative z-0 inline-flex shadow-sm rounded-md">
{#each siblings(currentParent, currentChild) as sibling}
<button type="button" on:click="{ e => switchTo(currentParent, sibling) }" class="relative inline-flex items-center px-4 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500">
{sibling.name}
</button>
{/each}
</span>
</div>
</div>
<div class="relative z-10" aria-labelledby="slide-over-title" role="dialog" aria-modal="true">
<!-- Background backdrop, show/hide based on slide-over state. -->
{#if sidePanelShown}
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"></div>
{/if}
<div class="fixed inset-0 overflow-hidden">
<div class="absolute inset-0 overflow-hidden">
<div class="pointer-events-none fixed inset-y-0 right-0 flex max-w-full pl-10">
{#if sidePanelShown}
<div class="pointer-events-auto w-screen max-w-md" transition:fly="{{ x: 200, duration: 600 }}">
<div class="flex h-full flex-col overflow-y-scroll bg-white py-6 shadow-xl">
<div class="px-4 sm:px-6">
<div class="flex items-start justify-between">
<h2 class="text-lg font-medium text-gray-900" id="slide-over-title">Panel title</h2>
<div class="ml-3 flex h-7 items-center">
<button on:click="{e => sidePanelShown = false}" type="button" class="rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">
<span class="sr-only">Close panel</span>
<!-- Heroicon name: outline/x -->
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
</div>
<div class="relative mt-6 flex-1 px-4 sm:px-6">
<!-- Replace with your content -->
<div class="absolute inset-0 px-4 sm:px-6">
<div class="h-full border-2 border-dashed border-gray-200" aria-hidden="true"></div>
</div>
<!-- /End replace -->
</div>
</div>
</div>
{/if}
</div>
</div>
</div>
</div>
<div class="grid grid-cols-1 gap-y-0 sm:grid-cols-2 mt-4">
{#each currentChild.children as grandchild, i (grandchild)}
<button on:click="{ e => switchTo(currentChild, grandchild) }" class="h-96 bg-{grandchild.color} hover:opacity-80 hover:scale-105">
<h3>{grandchild.name}</h3>
</button>
{/each}
</div>

Wyświetl plik

@ -1,6 +1,7 @@
<script>
import TopicMasonryGrid from "./TopicMasonryGrid.svelte"
export let alltopics;
</script>
<TopicMasonryGrid />
<TopicMasonryGrid {alltopics}/>

Wyświetl plik

@ -1,7 +1,7 @@
<script>
export let topicname; // undefined for top level
let topic;
let alltopics = [];
export let alltopics;
let map = new Map();
function capitalize(str){
@ -59,12 +59,7 @@
return tempmap;
}
$: fetch(`/learn/topics.json?_shape=array&_size=5000`)
.then(r => r.json())
.then(data => {
topic = data.find(t => t.name == topicname)
alltopics = data;
});
$: topic = alltopics.find(t => t.name == topicname)
$: map = hierarchy(alltopics, topic?.name || "")

Wyświetl plik

@ -4,6 +4,8 @@
let isNavDrawerOpen = false
export let showNotificationBell = false;
export let showProfileMenu = false;
export let alltopics;
import SearchForm from "./SearchForm.svelte"
</script>
@ -87,12 +89,13 @@
</div>
</div>
<div class="md:pl-64 flex flex-col flex-1">
<div class="sticky top-0 z-10 flex-shrink-0 flex h-16 bg-white shadow">
<div class="sticky top-0 z-10 flex-shrink-0 flex">
<button on:click={e => isNavDrawerOpen = true} type="button" class="px-4 border-r border-gray-200 text-gray-500 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500 md:hidden">
<span class="sr-only">Open sidebar</span>
<Icon kind="menu"/>
</button>
<div class="flex-1 px-4 flex justify-between">
<div class="flex-1 flex justify-between">
<SearchForm {alltopics}/>
{#if showNotificationBell || showProfileMenu}
<div class="ml-4 flex items-center md:ml-6">
{#if showNotificationBell}

Wyświetl plik

@ -0,0 +1,44 @@
<script>
export let options = [];
export let selected = {};
</script>
<div>
<div class="relative ml-2">
<input type="text" class="w-full rounded-md border border-gray-300 bg-white py-2 pl-3 pr-12 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 sm:text-sm" role="combobox" aria-controls="options" aria-expanded="false" value={selected && selected.label}>
<button type="button" class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
<!-- Heroicon name: solid/selector -->
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
<ul class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm" id="options" role="listbox">
{#each options as option}
<!--
Combobox option, manage highlight styles based on mouseenter/mouseleave and keyboard navigation.
Active: "text-white bg-indigo-600", Not Active: "text-gray-900"
-->
<li class="relative cursor-default select-none py-2 pl-3 pr-9 text-gray-900" role="option" tabindex="-1">
<!-- Selected: "font-semibold" -->
<span class={(selected && selected.value == option.value ? 'font-semibold' : '') + ' block truncate'}>{option.label}</span>
<!--
Checkmark, only display for selected option.
Active: "text-white", Not Active: "text-indigo-600"
-->
{#if selected && selected.value == option.value}
<span class="absolute inset-y-0 right-0 flex items-center pr-4 text-indigo-600">
<!-- Heroicon name: solid/check -->
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
</svg>
</span>
{/if}
</li>
{/each}
</ul>
</div>
</div>

Wyświetl plik

@ -1,6 +1,15 @@
<script>
import Icon from "./Icon.svelte"
let query;
import ComboBox from "./ComboBox.svelte"
export let alltopics;
let query = {
text: "some text",
topic: "algebra",
format: "book",
level: "beginner",
sortby: ""
};
let results = [];
function handleSubmit(ev){
@ -8,31 +17,35 @@
}
</script>
<form class="w-full flex md:ml-0" on:submit|preventDefault={handleSubmit}>
<label for="search-field" class="sr-only">Search</label>
<div class="relative w-full text-gray-400 focus-within:text-gray-600">
<div class="absolute inset-y-0 left-0 flex items-center pointer-events-none">
<Icon kind="search"/>
</div>
<input bind:value={query} class="block w-full h-full pl-8 pr-3 py-2 border-transparent text-gray-900 placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-0 focus:border-transparent sm:text-sm" placeholder="Search" type="search" name="search">
</div>
<form class="w-full bg-gray-100 p-2 inline-flex" on:submit|preventDefault={handleSubmit}>
<sl-input type="search" placeholder="Type something to search items by keywords" size="medium" clearable class="flex-1 border-0 p-0 focus:ring-0" value={query.text} on:sl-input="{e => query.text = e.target.value}">
<sl-icon name="search" slot="prefix"></sl-icon>
</sl-input>
<ComboBox options={alltopics.map(t => { return {label: t.display_name, value: t.name}; }).sort((a,b) => a.label.localeCompare(b.label))} selected={null}/>
<sl-select class="ml-2 w-44" on:sl-change="{e => query.format = e.target.value}" value={query.format}>
<sl-menu-item value="">Any format</sl-menu-item>
<sl-menu-item value="book">Books</sl-menu-item>
<sl-menu-item value="video">Videos</sl-menu-item>
<sl-menu-item value="audio">Podcasts</sl-menu-item>
</sl-select>
<sl-select class="ml-2 w-44" on:sl-change="{e => query.level = e.target.value}" value={query.level}>
<sl-menu-item value="">Any level</sl-menu-item>
<sl-menu-item value="childlike">Childlike</sl-menu-item>
<sl-menu-item value="beginner">Beginner</sl-menu-item>
<sl-menu-item value="intermediate">Intermediate</sl-menu-item>
<sl-menu-item value="advanced">Advanced</sl-menu-item>
<sl-menu-item value="research">Research</sl-menu-item>
</sl-select>
<sl-select class="ml-2 w-44" on:sl-change="{e => query.sortby = e.target.value}" value={query.sortby}>
<sl-icon name="sort-down-alt" slot="prefix"></sl-icon>
<sl-menu-item value="">Sort by</sl-menu-item>
<sl-menu-item value="rating">Rating</sl-menu-item>
<sl-menu-item value="year">Year</sl-menu-item>
<sl-menu-item value="name">Name</sl-menu-item>
</sl-select>
</form>
<ul class="max-h-80 scroll-pt-11 scroll-pb-2 space-y-2 overflow-y-auto pb-2" id="options" role="listbox">
<li>
<h2 class="bg-gray-100 py-2.5 px-4 text-xs font-semibold text-gray-900">Clients</h2>
<ul class="mt-2 text-sm text-gray-800">
<!-- Active: "bg-indigo-600 text-white" -->
<li class="cursor-default select-none px-4 py-2" id="option-1" role="option" tabindex="-1">Workflow Inc.</li>
<li class="cursor-default select-none px-4 py-2" id="option-2" role="option" tabindex="-1">Multinational LLC.</li>
</ul>
</li>
<li>
<h2 class="bg-gray-100 py-2.5 px-4 text-xs font-semibold text-gray-900">Projects</h2>
<ul class="mt-2 text-sm text-gray-800">
<!-- Active: "bg-indigo-600 text-white" -->
<li class="cursor-default select-none px-4 py-2" id="option-3" role="option" tabindex="-1">Workflow Inc. / Website Redesign</li>
<li class="cursor-default select-none px-4 py-2" id="option-3" role="option" tabindex="-1">Multinational LLC. / Animation</li>
</ul>
</li>
</ul>