Add tabs for lemmas #23

pull/43/head
Alexander Bentkamp 3 years ago
parent 7748eefa4a
commit a783e1dffc

@ -4,6 +4,7 @@
--clr-primary: #1976d2; --clr-primary: #1976d2;
--clr-light-gray: #ddd; --clr-light-gray: #ddd;
--clr-dark-gray: #aaa; --clr-dark-gray: #aaa;
--clr-darker-gray: #555;
--clr-code: rgba(0, 32, 90, 0.87); --clr-code: rgba(0, 32, 90, 0.87);
--ff-primary: Roboto; --ff-primary: Roboto;
--ff-code: "Roboto Mono"; --ff-code: "Roboto Mono";

@ -4,47 +4,66 @@ import './inventory.css'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faLock, faLockOpen, faBook, faHammer, faBan } from '@fortawesome/free-solid-svg-icons' import { faLock, faLockOpen, faBook, faHammer, faBan } from '@fortawesome/free-solid-svg-icons'
import Markdown from './Markdown'; import Markdown from './Markdown';
import { useLoadDocQuery } from '../state/api'; import { useLoadDocQuery, ComputedInventoryItem } from '../state/api';
function Inventory({ tactics, lemmas, definitions } : function Inventory({ tactics, lemmas, definitions } :
{lemmas: {name: string, locked: boolean, disabled: boolean}[], {lemmas: ComputedInventoryItem[],
tactics: {name: string, locked: boolean, disabled: boolean}[], tactics: ComputedInventoryItem[],
definitions: {name: string, locked: boolean, disabled: boolean}[]}) { definitions: ComputedInventoryItem[]}) {
const [docName, setDocName] = useState(null) const [docName, setDocName] = useState(null)
const [docType, setDocType] = useState(null) const [docType, setDocType] = useState(null)
function openDoc(name, type) {
setDocName(name)
setDocType(type)
}
return ( return (
<div className="inventory"> <div className="inventory">
{/* TODO: Click on Tactic: show info
TODO: click on paste icon -> paste into command line */}
<h2>Tactics</h2> <h2>Tactics</h2>
<div className="inventory-list"> <InventoryList items={tactics} docType="Tactic" openDoc={openDoc} />
{ tactics.map(tac =>
<InventoryItem key={tac.name} showDoc={() => {setDocName(tac.name); setDocType("Tactic")}}
name={tac.name} locked={tac.locked} disabled={tac.disabled} />) }
{/* TODO: Click on Tactic: show info
TODO: click on paste icon -> paste into command line */}
</div>
<h2>Definitions</h2> <h2>Definitions</h2>
<div className="inventory-list"> <InventoryList items={definitions} docType="Definition" openDoc={openDoc} />
{ definitions.map(def =>
<InventoryItem key={def.name} showDoc={() => {setDocName(def.name); setDocType("Definition")}}
name={def.name} locked={def.locked} disabled={def.disabled} />) }
</div>
<h2>Lemmas</h2> <h2>Lemmas</h2>
<div className="inventory-list"> <InventoryList items={lemmas} docType="Lemma" openDoc={openDoc} />
{ lemmas.map(lem =>
<InventoryItem key={lem.name} showDoc={() => {setDocName(lem.name); setDocType("Lemma")}}
name={lem.name} locked={lem.locked} disabled={lem.disabled} />) }
</div>
{docName && <Documentation name={docName} type={docType} />} {docName && <Documentation name={docName} type={docType} />}
</div> </div>
) )
} }
function InventoryList({items, docType, openDoc} : {items: ComputedInventoryItem[], docType: string, openDoc(name: string, type: string): void}) {
const categorySet = new Set<string>()
for (let item of items) {
categorySet.add(item.category)
}
const categories = Array.from(categorySet).sort()
const [tab, setTab] = useState(categories[0]);
return <>
{categories.length > 1 &&
<div className="tab-bar">
{categories.map((cat) =>
<div className={`tab ${cat == tab ? "active": ""}`} onClick={() => { setTab(cat) }}>{cat}</div>)}
</div>}
<div className="inventory-list">
{ items.map(item => {
if (tab == item.category) {
return <InventoryItem key={item.name} showDoc={() => {openDoc(item.name, docType)}}
name={item.name} locked={item.locked} disabled={item.disabled} />
}
}) }
</div>
</>
}
function InventoryItem({name, locked, disabled, showDoc}) { function InventoryItem({name, locked, disabled, showDoc}) {
const icon = locked ? <FontAwesomeIcon icon={faLock} /> : const icon = locked ? <FontAwesomeIcon icon={faLock} /> :
disabled ? <FontAwesomeIcon icon={faBan} /> : "" disabled ? <FontAwesomeIcon icon={faBan} /> : ""

@ -36,3 +36,25 @@
.inventory .item:not(.locked):not(.disabled) { .inventory .item:not(.locked):not(.disabled) {
cursor: pointer; cursor: pointer;
} }
.tab-bar {
border-bottom: 0.1em solid var(--clr-dark-gray);
margin-bottom: 0.5em;
}
.tab {
color: var(--clr-darker-gray);
line-height: inherit;
text-decoration: none;
padding: 0.2rem .6em;
font-size: 1rem;
margin: 0 .1em;
border: 0;
cursor: pointer;
display: inline-block;
}
.tab.active {
color: black;
border-bottom: 0.3em solid var(--clr-primary);
}

@ -10,13 +10,20 @@ interface GameInfo {
conclusion: null|string, conclusion: null|string,
} }
export interface ComputedInventoryItem {
name: string,
category: string,
disabled: boolean,
locked: boolean
}
interface LevelInfo { interface LevelInfo {
title: null|string, title: null|string,
introduction: null|string, introduction: null|string,
index: number, index: number,
tactics: {name: string, disabled: boolean, locked: boolean}[], tactics: ComputedInventoryItem[],
lemmas: {name: string, disabled: boolean, locked: boolean}[], lemmas: ComputedInventoryItem[],
definitions: {name: string, disabled: boolean, locked: boolean}[], definitions: ComputedInventoryItem[],
descrText: null|string, descrText: null|string,
descrFormat: null|string, descrFormat: null|string,
} }

@ -288,7 +288,7 @@ def GameLevel.getInventory (level : GameLevel) : InventoryType → InventoryInfo
| .Definition => level.definitions | .Definition => level.definitions
| .Lemma => level.lemmas | .Lemma => level.lemmas
def GameLevel.setComputedInventory (level : GameLevel) : InventoryType → Array Availability → GameLevel def GameLevel.setComputedInventory (level : GameLevel) : InventoryType → Array ComputedInventoryItem → GameLevel
| .Tactic, v => {level with tactics := {level.tactics with computed := v}} | .Tactic, v => {level with tactics := {level.tactics with computed := v}}
| .Definition, v => {level with definitions := {level.definitions with computed := v}} | .Definition, v => {level with definitions := {level.definitions with computed := v}}
| .Lemma, v => {level with lemmas := {level.lemmas with computed := v}} | .Lemma, v => {level with lemmas := {level.lemmas with computed := v}}
@ -314,19 +314,28 @@ elab "MakeGame" : command => do
newItemsInWorld := newItemsInWorld.insert worldId newItems newItemsInWorld := newItemsInWorld.insert worldId newItems
-- Basic inventory item availability: all locked, none disabled. -- Basic inventory item availability: all locked, none disabled.
let Availability₀ : HashMap Name Availability := let Availability₀ : HashMap Name ComputedInventoryItem :=
HashMap.ofList $ HashMap.ofList $
allItems.toList.map fun name => ← allItems.toList.mapM fun name => do
(name, {name, locked := true, disabled := false}) return (name, {
name
category := (← getInventoryDoc? name inventoryType).get!.category
locked := true
disabled := false})
-- Availability after a given world -- Availability after a given world
let mut itemsInWorld : HashMap Name (HashMap Name Availability) := {} let mut itemsInWorld : HashMap Name (HashMap Name ComputedInventoryItem) := {}
for (worldId, _) in game.worlds.nodes.toArray do for (worldId, _) in game.worlds.nodes.toArray do
let mut items := Availability₀ let mut items := Availability₀
let predecessors := game.worlds.predecessors worldId let predecessors := game.worlds.predecessors worldId
for predWorldId in predecessors do for predWorldId in predecessors do
for item in newItemsInWorld.find! predWorldId do for item in newItemsInWorld.find! predWorldId do
items := items.insert item {name := item, locked := false, disabled := false} items := items.insert item {
name := item
category := (← getInventoryDoc? item inventoryType).get!.category
locked := false
disabled := false
}
itemsInWorld := itemsInWorld.insert worldId items itemsInWorld := itemsInWorld.insert worldId items
for (worldId, world) in game.worlds.nodes.toArray do for (worldId, world) in game.worlds.nodes.toArray do
@ -336,9 +345,11 @@ elab "MakeGame" : command => do
for (levelId, level) in levels do for (levelId, level) in levels do
for item in (level.getInventory inventoryType).new do for item in (level.getInventory inventoryType).new do
items := items.insert item {name := item, locked := false, disabled := false} let category := (← getInventoryDoc? item inventoryType).get!.category
items := items.insert item {name := item, category, locked := false, disabled := false}
for item in (level.getInventory inventoryType).disabled do for item in (level.getInventory inventoryType).disabled do
items := items.insert item {name := item, locked := false, disabled := true} let category := (← getInventoryDoc? item inventoryType).get!.category
items := items.insert item {name := item, category, locked := false, disabled := true}
let itemsArray := items.toArray let itemsArray := items.toArray
|>.insertionSort (fun a b => a.1.toString < b.1.toString) |>.insertionSort (fun a b => a.1.toString < b.1.toString)

@ -30,7 +30,7 @@ structure GoalHintEntry where
/-! ## Tactic/Definition/Lemma documentation -/ /-! ## Tactic/Definition/Lemma documentation -/
inductive InventoryType := | Tactic | Lemma | Definition inductive InventoryType := | Tactic | Lemma | Definition
deriving ToJson, FromJson, Repr, BEq, Hashable deriving ToJson, FromJson, Repr, BEq, Hashable, Inhabited
instance : ToString InventoryType := ⟨fun t => match t with instance : ToString InventoryType := ⟨fun t => match t with
| .Tactic => "Tactic" | .Tactic => "Tactic"
@ -44,7 +44,7 @@ structure InventoryDocEntry where
userName : Name userName : Name
category : String category : String
content : String content : String
deriving ToJson, Repr deriving ToJson, Repr, Inhabited
/-- Environment extension for inventory documentation. -/ /-- Environment extension for inventory documentation. -/
initialize inventoryDocExt : SimplePersistentEnvExtension InventoryDocEntry (Array InventoryDocEntry) ← initialize inventoryDocExt : SimplePersistentEnvExtension InventoryDocEntry (Array InventoryDocEntry) ←
@ -118,8 +118,9 @@ structure LevelId where
level : Nat level : Nat
deriving Inhabited deriving Inhabited
structure Availability where structure ComputedInventoryItem where
name : Name name : Name
category : String
locked : Bool locked : Bool
disabled : Bool disabled : Bool
deriving ToJson, FromJson, Repr, Inhabited deriving ToJson, FromJson, Repr, Inhabited
@ -132,7 +133,7 @@ structure InventoryInfo where
-- only these inventory items are allowed in this level (ignored if empty): -- only these inventory items are allowed in this level (ignored if empty):
only : Array Name only : Array Name
-- inventory items in this level (computed by `MakeGame`): -- inventory items in this level (computed by `MakeGame`):
computed : Array Availability computed : Array ComputedInventoryItem
deriving ToJson, FromJson, Repr, Inhabited deriving ToJson, FromJson, Repr, Inhabited
def getCurLevelId [MonadError m] : m LevelId := do def getCurLevelId [MonadError m] : m LevelId := do

@ -42,9 +42,9 @@ Fields:
structure LevelInfo where structure LevelInfo where
index : Nat index : Nat
title : String title : String
tactics : Array Availability tactics : Array ComputedInventoryItem
lemmas : Array Availability lemmas : Array ComputedInventoryItem
definitions : Array Availability definitions : Array ComputedInventoryItem
introduction : String introduction : String
descrText : String := "" descrText : String := ""
descrFormat : String := "" descrFormat : String := ""
@ -58,9 +58,9 @@ structure LoadLevelParams where
structure DidOpenLevelParams where structure DidOpenLevelParams where
uri : String uri : String
levelModule : Name levelModule : Name
tactics : Array Availability tactics : Array ComputedInventoryItem
lemmas : Array Availability lemmas : Array ComputedInventoryItem
definitions : Array Availability definitions : Array ComputedInventoryItem
deriving ToJson, FromJson deriving ToJson, FromJson
structure Doc where structure Doc where

Loading…
Cancel
Save