Add tabs for lemmas #23
This commit is contained in:
@@ -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
-3
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user