GitHub Migration

This commit is contained in:
rarmknecht
2025-12-19 17:21:22 -06:00
commit b9f319436a
4 changed files with 435 additions and 0 deletions

74
forms.json Normal file
View File

@@ -0,0 +1,74 @@
[
{
"number": "1",
"name": "Kibon",
"handPosition": "Parallel Stance, Fists in Front",
"openingMove": "Turn Left forming a LEFT FOOT FORWARD FRONT STANCE while executing a HIGH FOREARM BLOCK"
},
{
"number": "2",
"name": "Kicho",
"handPosition": "Parallel Stance, Fists in Front",
"openingMove": "LEFT FOOT FORWARD FRONT STANCE while executing a LOW FOREARM BLOCK"
},
{
"number": "3",
"name": "Kyuki Il Chang",
"handPosition": "Closed Stance, Left Hand Straight Over Right Fist",
"openingMove": "Looking Left, Form a LEFT FOOT FOREWARD BACKSTANCE while executing a MIDDLE DOUBLE KNIFEHAND BLOCK"
},
{
"number": "4",
"name": "Kyuki Yee Chang",
"handPosition": "Closed Stance, Left Hand Straight Over Right Fist",
"openingMove": "Step Left Foot Back at 45 to form a RIGHT FOOT FORWARD BACK STANCE while executing a MIDDLE INSIDE FOREARM BLOCK"
},
{
"number": "5",
"name": "Kyuki Sam Chang",
"handPosition": "Closed Stance, Left Hand Straight Over Right Fist",
"openingMove": "Step Right Foot Back to form a LEFT FOOT FORWARD FRONT STANCE while executing a MIDDLE FOREARM BLOCK"
},
{
"number": "6",
"name": "Guen Bon",
"handPosition": "Parallel Stance, Double Arc Hand Pressing Earth",
"openingMove": "Step Right Foot Back to form a LEFT FOOT FORWARD FRONT STANCE while executing a LEFT LOW FOREARM BLOCK & RIGHT REVERSE MIDDLE INSIDE FOREARM BLOCK"
},
{
"number": "7",
"name": "Chonji In Il Chang",
"handPosition": "Parallel Stance, Double Arc Hand Pushing High",
"openingMove": "Stepping Left to form a LEFT FOOT FORWARD BACK STANCE while executing a LEFT CORKSCREW TRAP IN-TO-OUT"
},
{
"number": "8",
"name": "Chonji In Yee Chang",
"handPosition": "Parallel Stance, Double Arc Hand Pushing Low",
"openingMove": "Move left foot to form a HORSE STANCE facing forward. Execute a RIGHT ROLLING VERTICLE PUNCH with left hand under the right elbow"
},
{
"number": "9",
"name": "Chonji In Sam Chang",
"handPosition": "Parallel Stance, Double Arc Hand Pushing Middle",
"openingMove": "Stepping Back Left at 45 to form a CLASSICAL KYUKIDO STANCE while executing a LOW KYUKIDO BLOCK with left fist above the head"
},
{
"number": "10",
"name": "Man Nam",
"handPosition": "Closed Stance, Staff on Right Side",
"openingMove": "Step left foot out to parallel stance while executing a SLOW HIGH HORIZONTAL BLOCK"
},
{
"number": "11",
"name": "Ka Chi",
"handPosition": "Parallel Stance, Twin Verticle Spear Hands",
"openingMove": "Reach up with both hands executing a sleeve and lapel grab while executing a PROPPING ANKLE THROW with the right foot"
},
{
"number": "12",
"name": "Sa Rang",
"handPosition": "Parallel Stance, Open Hands Crossed Over Chest - Left Over Right",
"openingMove": "Step forward to form a LEFT FOOT FORWARD BACK STANCE and execute a LEFT INSIDE FOREARM BLOCK"
}
]

45
index.html Normal file
View File

@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Martial Arts Forms Flashcards</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h1>Martial Arts Forms Flashcards</h1>
<div class="flashcard-container">
<div class="flashcard" id="flashcard">
<div class="card-front">
<h2 id="form-name">Click to start</h2>
</div>
<div class="card-back">
<h2 id="form-number"></h2>
<div class="info-section">
<h3>Starting Hand Position:</h3>
<p id="hand-position"></p>
</div>
<div class="info-section">
<h3>Opening Move:</h3>
<p id="opening-move"></p>
</div>
</div>
</div>
</div>
<div class="controls">
<button id="prev-btn" disabled>Previous</button>
<span id="card-counter">0 / 0</span>
<button id="next-btn">Next</button>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progress-fill"></div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>

125
script.js Normal file
View File

@@ -0,0 +1,125 @@
class FlashcardApp {
constructor() {
this.forms = [];
this.currentIndex = 0;
this.isFlipped = false;
this.flashcard = document.getElementById('flashcard');
this.formName = document.getElementById('form-name');
this.formNumber = document.getElementById('form-number');
this.handPosition = document.getElementById('hand-position');
this.openingMove = document.getElementById('opening-move');
this.prevBtn = document.getElementById('prev-btn');
this.nextBtn = document.getElementById('next-btn');
this.cardCounter = document.getElementById('card-counter');
this.progressFill = document.getElementById('progress-fill');
this.init();
}
async init() {
try {
await this.loadForms();
this.setupEventListeners();
this.updateCard();
} catch (error) {
console.error('Error initializing app:', error);
this.showError('Failed to load forms data. Please check that forms.json exists.');
}
}
async loadForms() {
try {
const response = await fetch('forms.json');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
this.forms = await response.json();
if (!Array.isArray(this.forms) || this.forms.length === 0) {
throw new Error('Invalid forms data');
}
} catch (error) {
throw new Error(`Failed to load forms: ${error.message}`);
}
}
setupEventListeners() {
this.flashcard.addEventListener('click', () => this.flipCard());
this.prevBtn.addEventListener('click', () => this.previousCard());
this.nextBtn.addEventListener('click', () => this.nextCard());
document.addEventListener('keydown', (e) => {
switch(e.key) {
case 'ArrowLeft':
this.previousCard();
break;
case 'ArrowRight':
this.nextCard();
break;
case ' ':
case 'Enter':
e.preventDefault();
this.flipCard();
break;
}
});
}
flipCard() {
if (this.forms.length === 0) return;
this.isFlipped = !this.isFlipped;
this.flashcard.classList.toggle('flipped', this.isFlipped);
}
previousCard() {
if (this.forms.length === 0) return;
this.currentIndex = (this.currentIndex - 1 + this.forms.length) % this.forms.length;
this.updateCard();
}
nextCard() {
if (this.forms.length === 0) return;
this.currentIndex = (this.currentIndex + 1) % this.forms.length;
this.updateCard();
}
updateCard() {
if (this.forms.length === 0) return;
const currentForm = this.forms[this.currentIndex];
this.formNumber.textContent = currentForm.number;
this.formName.textContent = currentForm.name;
this.handPosition.textContent = currentForm.handPosition;
this.openingMove.textContent = currentForm.openingMove;
this.cardCounter.textContent = `${this.currentIndex + 1} / ${this.forms.length}`;
const progressPercent = ((this.currentIndex + 1) / this.forms.length) * 100;
this.progressFill.style.width = `${progressPercent}%`;
this.prevBtn.disabled = this.forms.length <= 1;
this.nextBtn.disabled = this.forms.length <= 1;
this.isFlipped = false;
this.flashcard.classList.remove('flipped');
}
showError(message) {
this.formName.textContent = 'Error';
this.handPosition.textContent = message;
this.openingMove.textContent = 'Please ensure forms.json exists in the same directory.';
this.cardCounter.textContent = '0 / 0';
this.progressFill.style.width = '0%';
this.prevBtn.disabled = true;
this.nextBtn.disabled = true;
}
}
document.addEventListener('DOMContentLoaded', () => {
new FlashcardApp();
});

191
styles.css Normal file
View File

@@ -0,0 +1,191 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
width: 100%;
max-width: 600px;
text-align: center;
}
h1 {
color: white;
margin-bottom: 30px;
font-size: 2.5rem;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.flashcard-container {
perspective: 1000px;
margin-bottom: 30px;
}
.flashcard {
width: 100%;
height: 400px;
position: relative;
transform-style: preserve-3d;
transition: transform 0.6s ease;
cursor: pointer;
}
.flashcard.flipped {
transform: rotateY(180deg);
}
.card-front, .card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 15px;
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 40px;
}
.card-front {
background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
color: #333;
}
.card-back {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
color: #333;
transform: rotateY(180deg);
}
.card-front h2 {
font-size: 2.5rem;
font-weight: bold;
text-align: center;
line-height: 1.2;
}
.info-section {
margin-bottom: 30px;
text-align: left;
width: 100%;
}
.info-section:last-child {
margin-bottom: 0;
}
.info-section h3 {
color: #495057;
font-size: 1.3rem;
margin-bottom: 10px;
border-bottom: 2px solid #007bff;
padding-bottom: 5px;
}
.info-section p {
font-size: 1.1rem;
line-height: 1.5;
color: #666;
}
.controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
button {
background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
color: white;
border: none;
padding: 12px 24px;
border-radius: 25px;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0,123,255,0.3);
}
button:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0,123,255,0.4);
}
button:disabled {
background: #6c757d;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
#card-counter {
color: white;
font-size: 1.1rem;
font-weight: bold;
background: rgba(255,255,255,0.2);
padding: 10px 20px;
border-radius: 20px;
backdrop-filter: blur(10px);
}
.progress-bar {
width: 100%;
height: 8px;
background: rgba(255,255,255,0.3);
border-radius: 10px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #28a745 0%, #20c997 100%);
width: 0%;
transition: width 0.3s ease;
border-radius: 10px;
}
@media (max-width: 768px) {
h1 {
font-size: 2rem;
}
.flashcard {
height: 350px;
}
.card-front h2 {
font-size: 2rem;
}
.info-section h3 {
font-size: 1.1rem;
}
.info-section p {
font-size: 1rem;
}
.controls {
flex-direction: column;
gap: 15px;
}
button {
width: 100%;
max-width: 200px;
}
}