diff --git a/WebSocketClient/assets/uvlTutorialContent.ts b/WebSocketClient/assets/uvlTutorialContent.ts index 6aaff41..862988d 100644 --- a/WebSocketClient/assets/uvlTutorialContent.ts +++ b/WebSocketClient/assets/uvlTutorialContent.ts @@ -1,9 +1,9 @@ export const tutorialContent = [{ title: "Welcome", - text: "Welcome to the UVL Tutorial! All code listings will automatically be placed in the editor on the left. Click 'Next' to start the tutorial." + text: "

Welcome to the UVL Tutorial!
All code listings will automatically be placed in the editor on the left. Click 'Next' to start the tutorial.

" }, { title: "Basic Feature Model", - text: "Start with the 'features' key word to start enumerating your features. Indentations matter in UVL and represent the tree structure. We will start with a basic feature model that represents a computer. Every computer needs a CPU and can optionaly have some devices connected via SATA.", + text: "

Start with the features key word to start enumerating your features. Indentations matter in UVL and represent the tree structure.
We will start with a basic feature model that represents a computer. Every computer needs a CPU and can optionaly have some devices connected via SATA.

", codeListing: `features Computer mandatory @@ -12,7 +12,7 @@ export const tutorialContent = [{ SATADevices` }, { title: "Special Feature Names", - text: "To use special characters or spaces in feature names use \" to enclose the names.", + text: "

To use special characters or spaces in feature names use \" to enclose the names.
In this example we write SATA-Devices with a dash instead of SATADevices.

", codeListing: `features Computer mandatory @@ -21,7 +21,7 @@ export const tutorialContent = [{ "SATA-Devices"` }, { title: "Basic Constraints", - text: "Use the 'constraints' keyword to start the section of constraints. In its basic form, a constraint uses propositional logic. In this example we enforce that if a computer contains a dedicated graphics card, it must also use liquid cooling. ", + text: "

Use the constraints keyword to start the section of constraints. In its basic form, a constraint uses propositional logic.
In this example we enforce that if a computer contains a dedicated graphics card, it must also use liquid cooling. We do that with the => symbol to represent an implication.
Other logic connectors are &, |, not

", codeListing: `features Computer mandatory @@ -41,7 +41,7 @@ constraints Dedicated => Liquid` }, { title: "Feature Attributes", - text: "Features can have attributes in curly brackets as key value pairs. The value can be omitted if it is a boolean attribute and the value is true. This is the case for the 'abstract' attribute in the feature 'Computer'. We also use attribues to indicate the power consumption of different parts of the computer.", + text: "

Features can have attributes in curly brackets as key value pairs. The value can be omitted if it is a boolean attribute and the value is true. This is the case for the abstract attribute in the feature Computer. We also use attribues to indicate the power consumption of different parts of the computer.

", codeListing: `features Computer {abstract} mandatory @@ -61,7 +61,7 @@ constraints Dedicated => Liquid` }, { title: "Complex Constraints", - text: "We can now create more complex constraints and for example access attribtues of features. In this case we use the aggregate function 'sum' to sum over all powerConsumption attributes and check if the overall powerConsumption is larger than a threshold and if so enforce a stronger power supply unit. You could also access feature attribtues and perform basic calculations with them.", + text: "

We can now create more complex constraints and for example access attribtues of features. In this case we use the aggregate function sum to sum over all powerConsumption attributes and check if the overall powerConsumption is larger than a threshold and if so enforce a stronger power supply unit. You could also access feature attribtues and perform basic calculations with them.

", codeListing: `features Computer {abstract} mandatory @@ -86,7 +86,7 @@ constraints sum(powerConsumption) > 300 => StrongPSU` }, { title: "Group Cardinality", - text: "Group cardinalities are more generic than 'or' and 'alternative'. In our example the motherboard only has space for up to 2 SATA-Devices. So we enforce that there are 0, 1, or 2 SATA-Devices.", + text: "

Group cardinalities are more generic than or and alternative.
In our example the motherboard only has space for up to 2 SATA-Devices. So we enforce that there are 0, 1, or 2 SATA-Devices.

", codeListing: `features Computer {abstract} mandatory @@ -115,7 +115,7 @@ constraints sum(powerConsumption) > 300 => StrongPSU` }, { title: "Feature Cardinality", - text: "Feature Cardinality allows a feature to be selected multiple times. In our example we can use up to 4 ram bars.", + text: "

Feature Cardinality allows a feature to be selected multiple times. In our example we can use up to 4 ram bars.

", codeListing: `features Computer {abstract} mandatory @@ -145,7 +145,7 @@ constraints sum(powerConsumption) > 300 => StrongPSU` }, { title: "Types", - text: "In UVL you can use types to create special features. In this case we change the power supply unit. It has a 'Manufacturer' feature of the type 'String' and a 'Watt' feature of the type 'Integer'. This means, when configuring the feature model, the features are not just selected or deselected, but get a value of their coresponding type. We can utilize this for even more complex constraints and check if the manufaturer of the CPU and the PSU match.", + text: "

In UVL you can use types to create special features. In this case we change the power supply unit. It has a Manufacturer feature of the type String and a Watt feature of the type Integer.
This means, when configuring the feature model, the features are not just selected or deselected, but get a value of their coresponding type. We can utilize this for even more complex constraints and check if the manufaturer of the CPU and the PSU match.

", codeListing: `features Computer {abstract} mandatory @@ -176,5 +176,5 @@ constraints CPU.Manufacturer == Manufacturer` }, { title: "The End", - text: "Now you have a basic understanding of the Universal Variablity Language. Go on and use the playground to test the language. If you plan on using the language more frequently we recommend installing an extension in an IDE of your choice, because it provides more features. Press the 'Done' button to close the tutorial." + text: "

Now you have a basic understanding of the Universal Variablity Language. Go on and use the playground to test the language.
If you plan on using the language more frequently we recommend installing an extension in an IDE of your choice, because it provides more features. Press the 'Done' button to close the tutorial.

" }] \ No newline at end of file diff --git a/WebSocketClient/src/uvlTutorial.ts b/WebSocketClient/src/uvlTutorial.ts index f20c892..31491e4 100644 --- a/WebSocketClient/src/uvlTutorial.ts +++ b/WebSocketClient/src/uvlTutorial.ts @@ -39,9 +39,10 @@ export default function initUvlTutorial(editor: editor.IStandaloneCodeEditor) { let newDiv = document.createElement('div'); newDiv.id = "uvl-tutorial-div"; let headline = document.createElement('h2'); + headline.textContent = content.title; let text = document.createElement('div'); - text.textContent = content.text; + text.innerHTML = content.text; text.className = 'text'; let navigationContainer = document.createElement('div'); diff --git a/WebSocketClient/style/style.css b/WebSocketClient/style/style.css index 1b3f922..7f52325 100644 --- a/WebSocketClient/style/style.css +++ b/WebSocketClient/style/style.css @@ -9,6 +9,10 @@ body { background-color: #1e1e1e; /* Dark background color */ } +h2 { + text-align: center; +} + .error { color: red; }