Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 27 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,45 @@
## @type-challenges/playground-plugin

> 🚧 WIP: Underheavly development, reach our [Discord](https://discord.gg/YtQu3QZu) for more details
[简体中文](./README.zh-CN.md)

TypeScript Playground Plugin for [Type Challenges](https://github.com/type-challenges/type-challenges)
TypeScript Playground Plugin for [Type Challenges](https://github.com/type-challenges/type-challenges).

## Running this plugin
![picture 1](images/31db67de83c2de209755814f2d892326846df0e1d03cf94a42e69228b1a181a0.gif)

- [Click this link](https://www.staging-typescript.org/play?install-plugin=@type-challenges/playground-plugin) to install ([currently broken](https://github.com/microsoft/TypeScript-Website/issues/1313))
Supported Features:

or
- [x] Pick question in challenge list
- [x] Switch languages
- [x] Copy and share answer to GitHub issue
- [x] Quick start next question
- [x] Quick find solutions

- Open up the TypeScript Playground
- Go the "Plugins" in the sidebar
- Look for "Plugins from npm"
- Add `@type-challenges/playground-plugin`
- Reload the browser
## Getting Started

Then it will show up as a tab in the sidebar.
### Step 1

[Open TypeScript Playground with Plugin](https://www.typescriptlang.org/play?install-plugin=%40type-challenges%2Fplayground-plugin)

### Step 2

![picture 2](images/e729298e337f291f715efdcb9fd5a7999d6563beb4fb27d9e845c681f75b3fe2.png)

Confirm "OK".

### Step 3

![picture 3](images/7d2e61ffca9179651ae071db60671f1c8c3500fb7d4d254f4322873d75ed422c.png)

Start the challenge in TypeScript Playground!

## Contributing

See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full details, however, TLDR:

```sh
git clone ...
yarn install
yarn
yarn start
```

Then tick the box for starting plugin development inside the TypeScript Playground.
tick the **Connect to localhost:5000** in bottom of Plugins Panel, and refresh browser page.
45 changes: 45 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## @type-challenges/playground-plugin

[English](./README.md)

在 TypeScript Playground 中轻松练习 [Type Challenges](https://github.com/type-challenges/type-challenges)。

![picture 1](images/31db67de83c2de209755814f2d892326846df0e1d03cf94a42e69228b1a181a0.gif)

功能支持:

- [x] 从题目列表中选择,直接进入答题模式
- [x] 语言切换
- [x] 复制答案跳转至 GitHub issue 进行分析
- [x] 下一题快捷按钮
- [x] 快速定位解答列表

## 起步

### 步骤一

[点击链接,打开 TypeScript Playground](https://www.typescriptlang.org/play?install-plugin=%40type-challenges%2Fplayground-plugin)

### 步骤二

![picture 2](images/e729298e337f291f715efdcb9fd5a7999d6563beb4fb27d9e845c681f75b3fe2.png)

确认安装插件。

### Step 3

![picture 3](images/7d2e61ffca9179651ae071db60671f1c8c3500fb7d4d254f4322873d75ed422c.png)

开始挑战吧!

## 如何贡献代码

完整信息请参阅 [CONTRIBUTING.md](./CONTRIBUTING.md),简单描述:

```sh
git clone ...
yarn
yarn start
```

勾选 Plugin 面板底部的 **Connect to localhost:5000** 选项,并刷新页面。
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"compile": "tsc",
"bootstrap": "ts-node scripts/getDTS.ts",
"dev": "yarn start",
"start": "concurrently -p \"[{name}]\" -n \"ROLLUP,SITE\" -c \"bgBlue.bold,bgMagenta.bold\" \"yarn rollup -c rollup.config.js --watch\" \"yarn serve dist\"",
"start": "concurrently -p \"[{name}]\" -n \"ROLLUP,SITE\" -c \"bgBlue.bold,bgMagenta.bold\" \"yarn rollup -c rollup.config.js --watch\" \"yarn serve dist -p 5000\"",
"prepublishOnly": "yarn build",
"postinstall": "yarn bootstrap && yarn build",
"release": "npx bumpp --commit --tag --push && yarn publish --non-interactive"
Expand All @@ -40,11 +40,11 @@
"node-fetch": "^2.6.0",
"rollup": "^1.31.0",
"rollup-plugin-svelte": "^6.1.1",
"serve": "^11.3.0",
"serve": "^13.0.2",
"svelte-check": "^1.1.13",
"svelte-preprocess": "^4.6.0",
"ts-node": "^9.0.0",
"typescript": "latest"
"typescript": "^4.5.2"
},
"dependencies": {
"svelte": "^3.29.7",
Expand Down
159 changes: 115 additions & 44 deletions src/components/App.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,101 @@
<script lang="ts">
import Description from './Description.svelte'
import TypeHelper from './TypeHelper.svelte'
import type { Context } from '../types'

export let context: Context

let active = 'desc'
let tabs: { name: string; text: string }[] = [
{ name: 'desc', text: 'Description' },
{ name: 'comments', text: 'Comments' },
{ name: 'solutions', text: 'Solutions' },
{ name: 'helper', text: 'Type Helper' },
]
import Description from "./Description.svelte";
import TypeHelper from "./TypeHelper.svelte";
import Challenges from "./Challenges.svelte";
import type { Context } from "../types";
import { onMount } from "svelte";
import { locale } from "../stores";
export let context: Context;

const tab2Panel = {
desc: Description,
helper: TypeHelper,
challenges: Challenges,
};
type TabPanelKey = keyof typeof tab2Panel;
interface IValidTab {
name: TabPanelKey;
text: string;
}
function isValidTab(tab: { name: string; text: string }): tab is IValidTab {
return tab.name in tab2Panel;
}
const tabs = [
{ name: "challenges", text: "Challenges" },
{ name: "desc", text: "Description" },
{ name: "comments", text: "Comments" },
{ name: "solutions", text: "Solutions" },
{ name: "helper", text: "Type Helper" },
].filter<IValidTab>(isValidTab);

let active: TabPanelKey = "challenges";
let currentQuiz: number = NaN;
let quizList: number[] = [];
onMount(() => {
const { sandbox } = context;
const sandboxText = sandbox.getText();
const matchLocale = sandboxText.match(
/\/\/tsch\.js\.org\/(\d+)?(?:\/([\w-]+)|)/
);

if (matchLocale) {
const [, quizNo, lang = ""] = matchLocale;
locale.set(lang);
if (!isNaN(+quizNo)) {
gotoQuestion(+quizNo);
}
}
});

function gotoQuestion(quizNo: number) {
active = "desc";
currentQuiz = quizNo;
}

function setQuizList(list: number[]) {
quizList = [...list];
}

function gotoNextQuestion(quizNo: number) {
const index = quizList.indexOf(quizNo);

if (index > -1 && index + 1 < quizList.length) {
gotoQuestion(quizList[index + 1]);
}
}
</script>

<div class="tab-container">
<nav>
{#each tabs as { name, text } (name)}
<button
role="tab"
class:active={active === name}
on:click={() => (active = name)}
>
{text}
</button>
{/each}
<div class="flex-auto" />
</nav>
<div class="panel">
<!-- We don't use `if` directive here because of keeping components alive. -->
<div class:hide={active !== "challenges"} class="inner">
<Challenges
{context}
toQuestion={gotoQuestion}
updateQuizList={setQuizList}
/>
</div>
<div class:hide={active !== "desc"} class="inner">
<Description {context} quiz={currentQuiz} toNext={gotoNextQuestion} />
</div>
<div class:hide={active !== "helper"} class="inner">
<TypeHelper {context} />
</div>
</div>
</div>

<style>
:global(#type-challenges) {
margin: 0 -0.7rem;
Expand All @@ -29,7 +111,14 @@
}

:root {
--border-color: rgba(125, 125, 125, 0.4);;
--border-color: rgba(125, 125, 125, 0.4);
}

.tab-container {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}

nav {
Expand All @@ -44,7 +133,7 @@
font-size: 14px;
width: 120px;
border: 1px solid var(--border-color);
transition: background .2s ease-in-out;
transition: background 0.2s ease-in-out;
}

nav button:not(:first-child) {
Expand All @@ -68,6 +157,16 @@
.panel {
padding: 0 1rem;
position: relative;
flex: 1;
overflow: hidden;
}

.panel .inner {
height: 100%;
overflow-y: auto;
margin-right: -1rem;
padding-right: 1rem;
overflow-x: hidden;
}

.footer {
Expand All @@ -77,38 +176,10 @@

.logo {
opacity: 0.25;
transition: opacity .5s ease-in-out;
transition: opacity 0.5s ease-in-out;
}

.logo:hover {
opacity: 0.5;
}
</style>

<nav>
{#each tabs as { name, text } (name)}
<button
role="tab"
class:active={active === name}
on:click={() => (active = name)}>
{text}
</button>
{/each}
<div class="flex-auto"/>
</nav>

<div class="panel">
<!-- We don't use `if` directive here because of keeping components alive. -->
<div class:hide={active !== 'desc'}>
<Description {context} />
</div>
<div class:hide={active !== 'helper'}>
<TypeHelper {context} />
</div>
</div>
<!--
<div class="footer">
<a class="logo" target="_blank" href="https://github.com/type-challenges/type-challenges">
<img src="https://raw.githubusercontent.com/type-challenges/type-challenges/master/screenshots/logo-dark.png" height="60" alt="Logo">
</a>
</div> -->
Loading