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
16 changes: 16 additions & 0 deletions templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en" data-theme="light">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css">
{% block head %}{% endblock %}
</head>

<body>
{% include 'components/github_ribbon.html' %}
{% block content %}{% endblock %}
</body>

</html>
240 changes: 175 additions & 65 deletions templates/challenge.html
Original file line number Diff line number Diff line change
@@ -1,46 +1,138 @@
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/codemirror.min.css"
/>
{% extends "base.html" %}

{% block head %}
{{ super() }}

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/codemirror.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/mode/python/python.min.js"></script>
<style>
html {
font-size: 1.2rem;
<title>Python Type Challenge - {{ name }}</title>

<style type="text/css">
.challenge-container {
display: flex;
padding: 1rem 2rem;
justify-content: center;
max-height: 100vh;
width: max(80vw, 80%);
}

/* Sidebar Area */
.sidebar-container {
display: flex;
flex-direction: column;
align-items: center;
margin-right: 2rem;
}

.sidebar-container .sidebar-challenge-list {
overflow-y: auto;
max-width: fit-content;
min-width: 100px;
}

.container {
.sidebar-container .sidebar-actions {
display: flex;
flex-direction: row;
justify-content: center;
margin: 0 auto;
width: 100%;
align-items: center;
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid hsl(205, 20%, 94%);
}

.navigation-container {
padding: 10px;
flex: 1;
/* Challenge Area */
.challenge-area {
display: flex;
flex-direction: column;
}

.codemirror-container {
padding: 10px;
.challenge-header__title {
display: flex;
align-items: center;
margin-bottom: 1rem;
}

.challenge-header__title > span:nth-child(1) {
font-size: 30px;
font-weight: bold;
margin-right: 20px;
}

.challenge-main {
display: flex;
justify-content: space-between;
gap: 24px;
}

/* Code Editor Area */
.challenge-main .codemirror-container {
display: flex;
flex-direction: column;
flex: 4;
gap: 16px;
width: 50%;
}

.result-container {
flex: 4;
.codemirror-container #run-button {
align-self: flex-end;
width: 100px;
padding: 2px 4px;
border-radius: 4px;
}

.tests-result-container {
display: flex;
justify-content: start;
margin-left: 10px;
flex-direction: column;
justify-content: space-between;
width: 50%;
gap: 16px;
}

.test-result-container #tests {
width: 50%;
}

/* 当视口宽度小于 800px 时,更改布局为单列 */
@media only screen and (max-width: 800px) {
.container {
.challenge-container {
flex-direction: column;
align-items: center;
margin-top: 20px;
height: 100%;
width: 100%;
}

.sidebar-container {
overflow-y: auto;
margin-right: 0;
margin-bottom: 2rem;
min-height: 100px;
}

.sidebar-container .sidebar-challenge-list {
height: 100%;
}

.challenge-header__title {
justify-content: space-between;
font-size: 14px;
}

.challenge-header__title > span:nth-child(1) {
margin-right: auto;
font-size: 20px;
}

.challenge-main {
flex-direction: column;
justify-content: center;
align-items: center;
gap: 0;
}

.challenge-main .codemirror-container,
.challenge-main .tests-result-container {
width: 100%;
}
}

Expand All @@ -53,67 +145,80 @@
border: 2px solid blue;
}

.code {
background-color: #ffffcc;
}
</style>
</head>

<body>
{% include 'github_ribbon.html' %}
<div class="container">
<div class="navigation-container">{% include 'challenge_list.html' %}</div>
<div class="codemirror-container">
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
"
>
<h2>Challenge - {{name}}</h2>
<p>Python version: {{ python_info }}</p>
{% endblock %}

{% block content %}
<div class="challenge-container container-fluid">
<!-- Left/Top Sidebar -->
<div class="sidebar-container">
<div class="sidebar-challenge-list">
{% include 'components/challenge_list.html' %}
</div>
<p style="margin-top: 0; line-height: 1.5">
<div class="sidebar-actions">
{% include 'components/darkmode.html' %}
</div>
</div>

<!-- Right/Bottom Challenge Area-->
<div class="challenge-area">
<!-- Challenge Header Area-->
<div class="challenge-header">
<div class="challenge-header__title">
<span>Challenge - {{ name }}</span>
{%include 'components/badge.html' with context %}
</div>
<p class="challenge-header__exerpt" style="margin-top: 0; line-height: 1.5">
Complete code following the instructions below, so that there are no type errors
throughout the test code except for those lines followed by a <code># expect-type-error</code> comment.
You don't need to implement the function, just add type annotations.
Hit the "Run" button to see result.
</p>
<div id="editor"></div>
<div style="display: flex; justify-content: flex-end">
<button id="run-button" style="width: 100px; margin-top: 10px">
</div>

<div class="challenge-main">
<!-- Code Editor Area -->
<div class="codemirror-container">
<div id="editor"></div>
<button id="run-button">
▶️ Run
</button>
</div>
<!-- Test Cases and Result Area -->
<div class="tests-result-container">
<div id="tests"></div>
<div id="result" style="white-space: pre-line"></div>
</div>
</div>
<p style="margin-top: 0">Test cases</p>
<div id="tests"></div>
</div>
<div class="result-container">
<p id="result" style="white-space: pre-line"></p>
</div>
</div>

<script type="text/javascript">
let code_under_test = {{code_under_test | tojson}};
console.log(code_under_test);
var myCodeMirror = CodeMirror(document.getElementById("editor"), {
value: code_under_test,
let codeMirrorShared = {
mode: "python",
lineWrapping: true,
lineNumbers: true,
indentUnit: 4
}
let code_under_test = {{ code_under_test | tojson }};
let myCodeMirror = CodeMirror(document.getElementById("editor"), {
value: code_under_test,
...codeMirrorShared,
});
let test_code = {{test_code | tojson}};
let test_code = {{ test_code | tojson }};
CodeMirror(document.getElementById("tests"), {
value: test_code,
mode: "python",
lineWrapping: true,
lineNumbers: true,
readOnly: "nocursor"
readOnly: "nocursor",
...codeMirrorShared,
});

document.getElementById('run-button').onclick = function () {
var code = myCodeMirror.getValue();
let runButton = document.getElementById('run-button')
runButton.onclick = function () {
// set button spinner
let rawInnerText = runButton.innerText;
runButton.ariaBusy = true;
runButton.innerText = ""

let code = myCodeMirror.getValue();
fetch('/run/{{name}}', {
method: 'POST',
body: code
Expand All @@ -122,12 +227,17 @@ <h2>Challenge - {{name}}</h2>
.then(result => document.getElementById("result").innerHTML = result)
.catch((error) => {
console.error('Error:', error);
})
.finally(() => {
// reset button spinner
runButton.ariaBusy = false;
runButton.innerText = rawInnerText;
});
};

// If window size is > 800, expand the challenge list.
function checkWidth() {
var detailsElement = document.getElementById('challenge-list');
let detailsElement = document.getElementById('challenge-list');
if (window.innerWidth < 800) {
detailsElement.removeAttribute('open');
} else {
Expand All @@ -137,4 +247,4 @@ <h2>Challenge - {{name}}</h2>
checkWidth(); // Check the width initially
window.addEventListener('resize', checkWidth);
</script>
</body>
{% endblock %}
36 changes: 36 additions & 0 deletions templates/components/badge.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

<head>
<style type="text/css">
.badge {
display: flex;
align-items: center;
justify-content: center;
padding: 2px 4px;
height: 30px;
border-radius: 5px;
background-color: #6cb8d4;
color: white;
font-size: 15px;
font-weight: bold;
}

.badge span:nth-child(1) svg {
width: 16px;
height: 16px;
margin-right: 5px;
}

.badge span:nth-child(2) {
font-size: 14px;
font-weight: lighter;
}
</style>
</head>


<div class="badge">
<span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 256 255"><defs><linearGradient id="logosPython0" x1="12.959%" x2="79.639%" y1="12.039%" y2="78.201%"><stop offset="0%" stop-color="#387EB8"/><stop offset="100%" stop-color="#366994"/></linearGradient><linearGradient id="logosPython1" x1="19.128%" x2="90.742%" y1="20.579%" y2="88.429%"><stop offset="0%" stop-color="#FFE052"/><stop offset="100%" stop-color="#FFC331"/></linearGradient></defs><path fill="url(#logosPython0)" d="M126.916.072c-64.832 0-60.784 28.115-60.784 28.115l.072 29.128h61.868v8.745H41.631S.145 61.355.145 126.77c0 65.417 36.21 63.097 36.21 63.097h21.61v-30.356s-1.165-36.21 35.632-36.21h61.362s34.475.557 34.475-33.319V33.97S194.67.072 126.916.072ZM92.802 19.66a11.12 11.12 0 0 1 11.13 11.13a11.12 11.12 0 0 1-11.13 11.13a11.12 11.12 0 0 1-11.13-11.13a11.12 11.12 0 0 1 11.13-11.13Z"/><path fill="url(#logosPython1)" d="M128.757 254.126c64.832 0 60.784-28.115 60.784-28.115l-.072-29.127H127.6v-8.745h86.441s41.486 4.705 41.486-60.712c0-65.416-36.21-63.096-36.21-63.096h-21.61v30.355s1.165 36.21-35.632 36.21h-61.362s-34.475-.557-34.475 33.32v56.013s-5.235 33.897 62.518 33.897Zm34.114-19.586a11.12 11.12 0 0 1-11.13-11.13a11.12 11.12 0 0 1 11.13-11.131a11.12 11.12 0 0 1 11.13 11.13a11.12 11.12 0 0 1-11.13 11.13Z"/></svg>
</span>
<span>{{ python_info }}</span>
</div>
Loading