Initial commit
This commit is contained in:
6
.env.development.example
Normal file
6
.env.development.example
Normal 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
6
.env.production.example
Normal 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
27
.gitignore
vendored
Normal 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
19
.prettierrc
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
13
index.html
Normal file
13
index.html
Normal 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
32
index.js
Normal 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
1960
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
package.json
Normal file
24
package.json
Normal 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
9
scripts/text_stimuli.js
Normal 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
1
styles.css
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
86
utils/deploy.js
Normal file
86
utils/deploy.js
Normal 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
5
utils/helpers.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export function delayed_redirect(url) {
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = url;
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
6
utils/html.js
Normal file
6
utils/html.js
Normal 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
46
vite.config.mjs
Normal 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,
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user