Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add routes #1

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
/tmp/*
!/log/.keep
!/tmp/.keep
/.idea/*

# Ignore pidfiles, but keep the directory.
/tmp/pids/*
Expand Down
2 changes: 1 addition & 1 deletion Procfile.dev
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
web: bin/rails server
web: bin/rails server --binding=192.168.22.110 -p 3000
css: bin/rails tailwindcss:watch
41 changes: 41 additions & 0 deletions app/controllers/tasks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,47 @@ def create
end
end

def edit
@task = Task.find(params[:id])
end

def update
@task = Task.find(params[:id])
respond_to do |format|
if @task.update(task_params)
format.html { redirect_to tasks_url, notice: "Task was successfully updated" }
else
format.html { render :edit, status: :unprocessable_entity }
end
end
end

def destroy
@task = Task.find(params[:id])
@task.destroy
redirect_to tasks_url, notice: "Post was successfully deleted."
end

def toggle
@task = Task.find(params[:id])
@task.update(completed: params[:completed])

render json: { message: "Success" }
end

def celebrate
Turbo::StreamsChannel.broadcast_replace_to(
"kinley_celeb",
target: 'kinley_celeb_frame',
html: render(
partial: 'shared/celebration',
locals: { path: '/' },
layout: false
)
)
head :no_content
end

private

def task_params
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/application.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
// import "controllers"
import "controllers"
// Turbo.session.drive = false
9 changes: 9 additions & 0 deletions app/javascript/controllers/application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Application } from "@hotwired/stimulus"

const application = Application.start()

// Configure Stimulus development experience
application.debug = false
window.Stimulus = application

export { application }
222 changes: 222 additions & 0 deletions app/javascript/controllers/celebration_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import {Controller} from "@hotwired/stimulus"

export default class extends Controller {
connect() {
var random = Math.random
, cos = Math.cos
, sin = Math.sin
, PI = Math.PI
, PI2 = PI * 2
, timer = undefined
, frame = undefined
, confetti = [];

var particles = 10
, spread = 40
, sizeMin = 3
, sizeMax = 12 - sizeMin
, eccentricity = 10
, deviation = 100
, dxThetaMin = -.1
, dxThetaMax = -dxThetaMin - dxThetaMin
, dyMin = .13
, dyMax = .18
, dThetaMin = .4
, dThetaMax = .7 - dThetaMin;

var colorThemes = [
function () {
return color(200 * random() | 0, 200 * random() | 0, 200 * random() | 0);
}, function () {
var black = 200 * random() | 0;
return color(200, black, black);
}, function () {
var black = 200 * random() | 0;
return color(black, 200, black);
}, function () {
var black = 200 * random() | 0;
return color(black, black, 200);
}, function () {
return color(200, 100, 200 * random() | 0);
}, function () {
return color(200 * random() | 0, 200, 200);
}, function () {
var black = 256 * random() | 0;
return color(black, black, black);
}, function () {
return colorThemes[random() < .5 ? 1 : 2]();
}, function () {
return colorThemes[random() < .5 ? 3 : 5]();
}, function () {
return colorThemes[random() < .5 ? 2 : 4]();
}
];

function color(r, g, b) {
return 'rgb(' + r + ',' + g + ',' + b + ')';
}

// Cosine interpolation
function interpolation(a, b, t) {
return (1 - cos(PI * t)) / 2 * (b - a) + a;
}

// Create a 1D Maximal Poisson Disc over [0, 1]
var radius = 1 / eccentricity, radius2 = radius + radius;

function createPoisson() {
// domain is the set of points which are still available to pick from
// D = union{ [d_i, d_i+1] | i is even }
var domain = [radius, 1 - radius], measure = 1 - radius2, spline = [0, 1];
while (measure) {
var dart = measure * random(), i, l, interval, a, b, c, d;

// Find where dart lies
for (i = 0, l = domain.length, measure = 0; i < l; i += 2) {
a = domain[i], b = domain[i + 1], interval = b - a;
if (dart < measure + interval) {
spline.push(dart += a - measure);
break;
}
measure += interval;
}
c = dart - radius, d = dart + radius;

// Update the domain
for (i = domain.length - 1; i > 0; i -= 2) {
l = i - 1, a = domain[l], b = domain[i];
// c---d c---d Do nothing
// c-----d c-----d Move interior
// c--------------d Delete interval
// c--d Split interval
// a------b
if (a >= c && a < d)
if (b > d) domain[l] = d; // Move interior (Left case)
else domain.splice(l, 2); // Delete interval
else if (a < c && b > c)
if (b <= d) domain[i] = c; // Move interior (Right case)
else domain.splice(i, 0, c, d); // Split interval
}

// Re-measure the domain
for (i = 0, l = domain.length, measure = 0; i < l; i += 2)
measure += domain[i + 1] - domain[i];
}

return spline.sort();
}

// Create the overarching container
var container = document.createElement('div');
container.style.position = 'fixed';
container.style.top = '0';
container.style.left = '0';
container.style.width = '100%';
container.style.height = '0';
container.style.overflow = 'visible';
container.style.zIndex = '9999';

// Confetto constructor
function Confetto(theme) {
this.frame = 0;
this.outer = document.createElement('div');
this.inner = document.createElement('div');
this.outer.appendChild(this.inner);

var outerStyle = this.outer.style, innerStyle = this.inner.style;
outerStyle.position = 'absolute';
outerStyle.width = (sizeMin + sizeMax * random()) + 'px';
outerStyle.height = (sizeMin + sizeMax * random()) + 'px';
innerStyle.width = '100%';
innerStyle.height = '100%';
innerStyle.backgroundColor = theme();

outerStyle.perspective = '50px';
outerStyle.transform = 'rotate(' + (360 * random()) + 'deg)';
this.axis = 'rotate3D(' +
cos(360 * random()) + ',' +
cos(360 * random()) + ',0,';
this.theta = 360 * random();
this.dTheta = dThetaMin + dThetaMax * random();
innerStyle.transform = this.axis + this.theta + 'deg)';

this.x = window.innerWidth * random();
this.y = -deviation;
this.dx = sin(dxThetaMin + dxThetaMax * random());
this.dy = dyMin + dyMax * random();
outerStyle.left = this.x + 'px';
outerStyle.top = this.y + 'px';

// Create the periodic spline
this.splineX = createPoisson();
this.splineY = [];
for (var i = 1, l = this.splineX.length - 1; i < l; ++i)
this.splineY[i] = deviation * random();
this.splineY[0] = this.splineY[l] = deviation * random();

this.update = function (height, delta) {
this.frame += delta;
this.x += this.dx * delta;
this.y += this.dy * delta;
this.theta += this.dTheta * delta;

// Compute spline and convert to polar
var phi = this.frame % 7777 / 7777, i = 0, j = 1;
while (phi >= this.splineX[j]) i = j++;
var rho = interpolation(
this.splineY[i],
this.splineY[j],
(phi - this.splineX[i]) / (this.splineX[j] - this.splineX[i])
);
phi *= PI2;

outerStyle.left = this.x + rho * cos(phi) + 'px';
outerStyle.top = this.y + rho * sin(phi) + 'px';
innerStyle.transform = this.axis + this.theta + 'deg)';
return this.y > height + deviation;
};
}

function poof() {
if (!frame) {
// Append the container
document.body.appendChild(container);

// Add confetti
var theme = colorThemes[0]
, count = 0;
(function addConfetto() {
var confetto = new Confetto(theme);
confetti.push(confetto);
container.appendChild(confetto.outer);
timer = setTimeout(addConfetto, spread * random());
})(0);

// Start the loop
var prev = undefined;
requestAnimationFrame(function loop(timestamp) {
var delta = prev ? timestamp - prev : 0;
prev = timestamp;
var height = window.innerHeight;

for (var i = confetti.length - 1; i >= 0; --i) {
if (confetti[i].update(height, delta)) {
container.removeChild(confetti[i].outer);
confetti.splice(i, 1);
}
}

if (timer || confetti.length)
return frame = requestAnimationFrame(loop);

// Cleanup
document.body.removeChild(container);
frame = undefined;
});
}
}

poof();
};
}

12 changes: 12 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Import and register all your controllers from the importmap under controllers/*

import {application} from "controllers/application"

// Eager load all controllers defined in the import map under controllers/**/*_controller
import {eagerLoadControllersFrom} from "@hotwired/stimulus-loading"

eagerLoadControllersFrom("controllers", application)

// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
// lazyLoadControllersFrom("controllers", application)
28 changes: 28 additions & 0 deletions app/javascript/controllers/tasks_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {Controller} from "@hotwired/stimulus"

export default class extends Controller {
connect() {
console.log(this.element)
}

toggle(e) {
const id = e.target.dataset.id
const csrfToken = document.querySelector("[name='csrf-token']").content

fetch(`/tasks/${id}/toggle`, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
},
body: JSON.stringify({completed: e.target.checked}) // body data type must match "Content-Type" header
})
.then(response => response.json())
.then(data => {
alert(data.message)
})
}
}
2 changes: 2 additions & 0 deletions app/views/shared/_celebration.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<div id="confetti-container" data-controller="celebration">
</div>
25 changes: 22 additions & 3 deletions app/views/tasks/_task.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
<div class="block mb-2">
<%= task.description %>
</div>
<turbo-frame id="<%= dom_id task %>" class="block">
<div class="block">
<%= form_with(model: task, class: "text-lg inline-block my-3 w-72") do |form| %>
<%= form.check_box :completed,
data: {
id: task.id,
action: "tasks#toggle"
},
class: "mr-2 align-middle bg-gray-50 border-gray-300 focus:ring-3 focus:ring-blue-300 h-5 w-5 rounded checked:bg-green-500" %>
<%= task.description %>
<% end %>

<%= link_to "Edit", edit_task_path(task),
class: "btn bg-gray-100"
%>
<div class="inline-block ml-2">
<%= button_to "Delete", task_path(task),
method: :delete,
class: "btn bg-red-100" %>
</div>
</div>
</turbo-frame>
8 changes: 8 additions & 0 deletions app/views/tasks/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div>
<h1 class="font-bold text-2xl mb-3">Editing Task</h1>

<turbo-frame id="<%= dom_id @task %>">
<%= render "form", task: @task %>
<%= link_to "Never Mind", tasks_path, class: "btn mb-3 bg-gray-100" %>
</turbo-frame>
</div>
Loading