Initial commit

This commit is contained in:
2025-07-01 07:41:47 -07:00
commit 2761943d9d
15 changed files with 2242 additions and 0 deletions

6
.env.development.example Normal file
View File

@@ -0,0 +1,6 @@
VITE_DEBUG=true
VITE_COMPLETE_URL=
VITE_CLOSED_URL=
VITE_EXPERIMENT_TITLE=
VITE_EXPERIMENT_NAME=
VITE_DEPLOY_URL=

6
.env.production.example Normal file
View File

@@ -0,0 +1,6 @@
VITE_DEBUG=false
VITE_COMPLETE_URL=
VITE_CLOSED_URL=
VITE_EXPERIMENT_TITLE=
VITE_EXPERIMENT_NAME=
VITE_DEPLOY_URL=

27
.gitignore vendored Normal file
View File

@@ -0,0 +1,27 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.env.production
.env.development

19
.prettierrc Normal file
View File

@@ -0,0 +1,19 @@
{
"printWidth": 80,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "es5",
"htmlWhitespaceSensitivity": "ignore",
"plugins": ["prettier-plugin-html-template-literals"],
"overrides": [
{
"files": ["*.js"],
"options": {
"htmlTemplateLiterals": {
"indent": 2,
"format": true
}
}
}
]
}

2
README.md Normal file
View File

@@ -0,0 +1,2 @@
# jspsych-npm-template

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link href="/styles.css" rel="stylesheet" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/index.js"></script>
</body>
</html>

32
index.js Normal file
View File

@@ -0,0 +1,32 @@
import { initJsPsych } from "jspsych";
import "jspsych/css/jspsych.css";
import "./styles.css";
import { delayed_redirect } from "./utils/helpers.js";
import jsPsychHtmlKeyboardResponse from "@jspsych/plugin-html-keyboard-response";
import { textStimuli } from './scripts/text_stimuli';
const debug = import.meta.env.VITE_DEBUG;
const jsPsych = initJsPsych({
on_finish: function() {
jsPsych.getDisplayElement().innerHTML = textStimuli.complete;
},
on_close: function() {
delayed_redirect(import.meta.env.VITE_CLOSED_URL);
},
on_data_update: function() {
if (debug) {
console.log(jsPsych.data.get().json());
}
},
});
const demo_trial = {
type: jsPsychHtmlKeyboardResponse,
stimulus: `<h1 class="text-2xl font-bold">Hello, world!</h1>`,
choices: [''],
};
const timeline = [demo_trial];
jsPsych.run(timeline);

1960
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

24
package.json Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "jspsych-npm-template",
"private": true,
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"deploy": "npm run build && NODE_ENV=production node scripts/deploy.js",
"deploy-dev": "npm run build && NODE_ENV=development node scripts/deploy.js"
},
"devDependencies": {
"terser": "^5.39.0",
"vite": "^6.3.1"
},
"dependencies": {
"@jspsych/plugin-html-keyboard-response": "^2.1.0",
"@tailwindcss/vite": "^4.1.4",
"jspsych": "^8.2.1",
"prettier-plugin-html-template-literals": "^1.0.5",
"tailwindcss": "^4.1.4",
"vite-plugin-static-copy": "^3.0.0"
}
}

9
scripts/text_stimuli.js Normal file
View File

@@ -0,0 +1,9 @@
import html from '../utils/html.js';
export const textStimuli = {
complete: html`Experiment complete. Please paste the following link into your browser to confirm completion on Prolific:
<span class="text-blue-500">
${import.meta.env.VITE_COMPLETE_URL}
</a>
`,
};

1
styles.css Normal file
View File

@@ -0,0 +1 @@
@import "tailwindcss";

86
utils/deploy.js Normal file
View File

@@ -0,0 +1,86 @@
const { execSync } = require('child_process');
const path = require('path');
const fs = require('fs');
const archiver = require('archiver');
const dotenv = require('dotenv');
// Load environment variables based on NODE_ENV
const envFile =
process.env.NODE_ENV === 'production'
? '.env.production'
: '.env.development';
dotenv.config({ path: path.join(__dirname, '..', envFile) });
// Function to create and send zip file
function sendZipFile() {
return new Promise((resolve, reject) => {
const distPath = path.join(__dirname, '../dist');
const zipPath = path.join(__dirname, '../dist.zip');
// Create a file to stream archive data to
const output = fs.createWriteStream(zipPath);
const archive = archiver('zip', {
zlib: { level: 9 }, // Sets the compression level
});
// Listen for all archive data to be written
output.on('close', () => {
console.log(`✅ Archive created: ${archive.pointer()} total bytes`);
// Get the deployment URL from environment
const deployUrl = process.env.VITE_DEPLOY_URL;
if (!deployUrl) {
console.error('❌ VITE_DEPLOY_URL not found in environment variables');
process.exit(1);
}
// Send the zip file via curl
try {
console.log(`📤 Sending zip file to ${deployUrl}...`);
execSync(`curl -X POST -F "file=@${zipPath}" ${deployUrl}`, {
stdio: 'inherit',
});
console.log('✅ Zip file sent successfully');
} catch (error) {
console.error('❌ Failed to send zip file:', error.message);
process.exit(1);
}
// Clean up the zip file
fs.unlinkSync(zipPath);
resolve();
});
// Handle warnings and errors
archive.on('warning', err => {
if (err.code === 'ENOENT') {
console.warn('⚠️ Archive warning:', err);
} else {
reject(err);
}
});
archive.on('error', err => {
reject(err);
});
// Pipe archive data to the file
archive.pipe(output);
// Add the dist directory to the archive
archive.directory(distPath, false);
// Finalize the archive
archive.finalize();
});
}
// Run the deployment
sendZipFile()
.then(() => {
console.log('✅ Deployment successful!');
})
.catch(error => {
console.error('❌ Deployment failed:', error.message);
process.exit(1);
});

5
utils/helpers.js Normal file
View File

@@ -0,0 +1,5 @@
export function delayed_redirect(url) {
setTimeout(() => {
window.location.href = url;
}, 5000);
}

6
utils/html.js Normal file
View File

@@ -0,0 +1,6 @@
const html = (strings, ...values) =>
strings
.reduce((result, str, i) => result + str + (values[i] || ""), "")
.trim();
export default html;

46
vite.config.mjs Normal file
View File

@@ -0,0 +1,46 @@
import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite';
import { viteStaticCopy } from 'vite-plugin-static-copy';
export default defineConfig({
base: './', // This makes all assets use relative paths
plugins: [
tailwindcss(),
viteStaticCopy({
targets: [
{
src: 'images/*',
dest: 'images',
},
],
}),
],
server: {
watch: {
usePolling: true,
},
},
build: {
minify: false,
terserOptions: {
compress: false,
mangle: false,
},
rollupOptions: {
input: {
main: 'index.html',
},
output: {
format: 'iife',
entryFileNames: '[name].js',
chunkFileNames: '[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash].[ext]',
sanitizeFileName: name => name.replace(/\.[jt]sx?$/, ''),
},
},
assetsInlineLimit: 0,
target: 'esnext',
modulePreload: false,
cssCodeSplit: false,
},
});