OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)

This commit is contained in:
wangruiguo
2026-09-03 18:49:20 +08:00
commit d647428529
3501 changed files with 1988906 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Andy Roche
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,10 @@
# pomodoro
#### A simple pomodoro timer written in JavaScript. Find it at http://roche.io/pomodoro/
There are plenty of timers like this online ([Moosti](http://moosti.com/), [Tomato Timer](http://tomato-timer.com/)), but the best workflow tool is the one you use. This was a quick side project for me in September 2015 to brush up on my web development and build something I would use myself. It takes the best features from all of the similar timers, and drops the cruft.
#### Features:
- Minutes remaining shown in browser tab
- Favicon change and alarm on timer complete (alarms provided by [AndYouAreWho](http://soundcloud.com/andyouarewho))
- Keyboard shortcuts using Mousetrap.js (hit space to pause/resume)
- Custom time with adjustable units

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,104 @@
body {
margin: auto;
text-align: center;
}
header {
padding-bottom: 10px;
border-bottom: thin solid #777;
font-family: 'Indie Flower', cursive;
}
label {
padding: 0;
margin: 0;
}
h1 {
margin-top: 5px;
margin-bottom: 15px;
padding: 0;
font-family: 'Indie Flower', cursive;
font-size: 2em;
font-weight: bold;
}
footer {
padding: 10px 0px;
border-top: thin solid #777;
}
#title {
font-size: 4em;
font-weight: bold;
}
#subtitle {
font-size: 1.5em;
}
.content {
padding: 20px 0px 40px 0px;
}
#timer {
font-size: 6em;
font-weight: bold;
}
button.btn_default {
padding: 8px 12px;
margin: 2px 0px;
font-weight: bold;
border-radius: 4px;
-webkit-border-radius: 4px;
border: 1px solid;
}
#btn_start {
background-color: #9F9;
border: 1px solid #171;
}
#btn_pause {
background-color: #FF9;
border: 1px solid #771;
}
#btn_reset {
background-color: #F99;
border: 1px solid #711;
}
#ipt_custom {
padding: 8px 12px;
width: 75px;
border-radius: 4px;
-webkit-border-radius: 4px;
border: 1px solid;
text-align: center;
}
#custom_units {
padding: 8px 12px;
border-radius: 4px;
-webkit-border-radius: 4px;
border: 1px solid;
text-align: center;
}
div.footerbox {
max-width: 300px;
margin: 10px 5px;
display: inline-block;
vertical-align: top;
background-color: #EEE;
padding: 8px 12px;
border-radius: 8px;
-webkit-border-radius: 8px;
border: 1px solid;
}
div.footerbox ol {
display: inline-block;
text-align: left;
padding-left: 15px;
}
#options {
text-align: left;
}
#options label {
margin-bottom: 5px;
}
#options select {
width: 100%;
margin-bottom: 20px;
}
.credits {
margin: 2em 0;
color: #999;
}

View File

@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title id="tab_title">Pomodoro</title>
<link id="dynamic-favicon" rel="icon" type="image/ico"
href="images/red_tomato.ico">
<!-- Original favicon courtesy of http://icons8.com -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel='stylesheet' type='text/css'
href='http://fonts.googleapis.com/css?family=Indie+Flower'>
<link rel="stylesheet" href="pomodoro.css">
</head>
<body>
<div class="container">
<header>
<div id="titlebox">
<div id="title">Pomodoro</div>
<div id="subtitle">A simple workflow tool</div>
</div>
</header>
<div class="content">
<p>
<div><span id="timer"></span></div>
<button id="btn_start" class="btn_default">start</button>
<button id="btn_pause" class="btn_default">pause</button>
<button id="btn_reset" class="btn_default">reset</button>
</p>
<p>
<button id="btn_pomodoro" class="btn_default">pomodoro (25m)</button>
<button id="btn_shortbreak" class="btn_default">short break (5m)</button>
<button id="btn_longbreak" class="btn_default">long break (15m)</button>
</p>
<p>
<button id="btn_custom" class="btn_default">
<label for="ipt_custom">custom:</label>
</button>
<input type="number" id="ipt_custom" value="45" min="0" max="100000000">
<select id="custom_units">
<option value="seconds">seconds</option>
<option value="minutes" selected>minutes</option>
<option value="hours">hours</option>
</select>
</p>
</div>
<footer>
<div class="footerbox">
<h1>How it works:</h1>
<ol>
<li>Choose a task to focus on</li>
<li>Work for 25 uninterrupted minutes</li>
<li>Break for 5 minutes</li>
<li>Every four cycles, take a 15-30 minute<br>
break instead, preferably outside</li>
</ol>
<br>
<a href="https://en.wikipedia.org/wiki/Pomodoro_Technique" target="_blank">
Read more at Wikipedia
</a>
</div>
<div class="footerbox">
<h1>Options:</h1>
<div id="options">
<label for="alarm_select" id="lbl_alarm">Alarm:</label><br>
<select id="alarm_select">
<option value="none">None</option>
<option value="alarm_chime">Chime</option>
<option value="alarm_bell" selected>Bell</option>
<option value="alarm_beeps">Beeps</option>
<option value="alarm_boops">Boops</option>
</select>
<br><br>
<label for="alarm_volume" id="lbl_volume">Volume:</label><br>
<input type="range" id="alarm_volume" min=0 max=100 value=50>
</div>
<br>
</div>
<div class="credits">
Created by
<a href="../index.html">Andy Roche</a> -
<a href="https://github.com/rocheio/rocheio.github.io/tree/master/pomodoro">Github</a>
</div>
</footer>
</div>
<audio id="alarm_chime">
<source src="audio/one_chime.mp3" type="audio/mpeg"></audio>
<audio id="alarm_bell">
<source src="audio/one_bell.mp3" type="audio/mpeg"></audio>
<audio id="alarm_beeps">
<source src="audio/three_beeps.mp3" type="audio/mpeg"></audio>
<audio id="alarm_boops">
<source src="audio/three_boops.mp3" type="audio/mpeg"></audio>
<!-- Audio courtesy of https://soundcloud.com/andyouarewho -->
<script type="text/javascript" src="../resources/mousetrap.js"></script>
<script type="text/javascript" src="pomodoro.js"></script>
</body>
</html>

View File

@@ -0,0 +1,222 @@
/** Represents a timer that can count down. */
function CountdownTimer(seconds, tickRate) {
this.seconds = seconds || (25*60);
this.tickRate = tickRate || 500; // Milliseconds
this.tickFunctions = [];
this.isRunning = false;
this.remaining = this.seconds;
/** CountdownTimer starts ticking down and executes all tick
functions once per tick. */
this.start = function() {
if (this.isRunning) {
return;
}
this.isRunning = true;
// Set variables related to when this timer started
var startTime = Date.now(),
thisTimer = this;
// Tick until complete or interrupted
(function tick() {
secondsSinceStart = ((Date.now() - startTime) / 1000) | 0;
var secondsRemaining = thisTimer.remaining - secondsSinceStart;
// Check if timer has been paused by user
if (thisTimer.isRunning === false) {
thisTimer.remaining = secondsRemaining;
} else {
if (secondsRemaining > 0) {
// Execute another tick in tickRate milliseconds
setTimeout(tick, thisTimer.tickRate);
} else {
// Stop this timer
thisTimer.remaining = 0;
thisTimer.isRunning = false;
// Alert user that time is up
playAlarm();
changeFavicon('green');
}
var timeRemaining = parseSeconds(secondsRemaining);
// Execute each tickFunction in the list with thisTimer
// as an argument
thisTimer.tickFunctions.forEach(
function(tickFunction) {
tickFunction.call(this,
timeRemaining.minutes,
timeRemaining.seconds);
},
thisTimer);
}
}());
};
/** Pause the timer. */
this.pause = function() {
this.isRunning = false;
};
/** Pause the timer and reset to its original time. */
this.reset = function(seconds) {
this.isRunning = false;
this.seconds = seconds
this.remaining = seconds
};
/** Add a function to the timer's tickFunctions. */
this.onTick = function(tickFunction) {
if (typeof tickFunction === 'function') {
this.tickFunctions.push(tickFunction);
}
};
}
/** Return minutes and seconds from seconds. */
function parseSeconds(seconds) {
return {
'minutes': (seconds / 60) | 0,
'seconds': (seconds % 60) | 0
}
}
/** Play the selected alarm at selected volume. */
function playAlarm() {
var alarmValue = document.getElementById('alarm_select').value;
if (alarmValue != 'none') {
var alarmAudio = document.getElementById(alarmValue);
var alarmVolume = document.getElementById('alarm_volume').value;
alarmAudio.volume = alarmVolume / 100;
alarmAudio.play();
}
}
/** Change the color of the favicon. */
function changeFavicon(color) {
document.head = document.head || document.getElementsByTagName('head')[0];
var color = color || 'green';
var newFavicon = document.createElement('link'),
oldFavicon = document.getElementById('dynamic-favicon');
newFavicon.id = 'dynamic-favicon'
newFavicon.type = 'image/ico';
newFavicon.rel = 'icon';
newFavicon.href = 'images/' + color + '_tomato.ico';
if (oldFavicon) {
document.head.removeChild(oldFavicon);
}
document.head.appendChild(newFavicon);
}
/** Window onload functions. */
window.onload = function () {
var timerDisplay = document.getElementById('timer'),
customTimeInput = document.getElementById('ipt_custom'),
timer = new CountdownTimer(),
timeObj = parseSeconds(25*60);
/** Set the time on the main clock display and
set the time remaining section in the title. */
function setTimeOnAllDisplays(minutes, seconds) {
if (minutes >= 60) {
// Add an hours section to all displays
hours = Math.floor(minutes / 60);
minutes = minutes % 60;
clockHours = hours + ':';
document.title = '(' + hours + 'h' + minutes + 'm) Pomodoro';
} else {
clockHours = '';
document.title = '(' + minutes + 'm) Pomodoro';
}
clockMinutes = minutes < 10 ? '0' + minutes : minutes;
clockMinutes += ':';
clockSeconds = seconds < 10 ? '0' + seconds : seconds;
timerDisplay.textContent = clockHours + clockMinutes + clockSeconds;
}
/** Revert the favicon to red, delete the old timer
object, and start a new one. */
function resetMainTimer(seconds) {
changeFavicon('red');
timer.pause();
timer = new CountdownTimer(seconds);
timer.onTick(setTimeOnAllDisplays);
}
// Set default page timer displays
setTimeOnAllDisplays(timeObj.minutes, timeObj.seconds);
timer.onTick(setTimeOnAllDisplays);
// Add listeners for start, pause, etc. buttons
document.getElementById('btn_start').addEventListener(
'click', function () {
timer.start();
});
document.getElementById('btn_pause').addEventListener(
'click', function () {
timer.pause();
});
document.getElementById('btn_reset').addEventListener(
'click', function () {
resetMainTimer(timer.seconds);
timer.start();
});
document.getElementById('btn_pomodoro').addEventListener(
'click', function () {
resetMainTimer(25*60);
timer.start();
});
document.getElementById('btn_shortbreak').addEventListener(
'click', function () {
resetMainTimer(5*60);
timer.start();
});
document.getElementById('btn_longbreak').addEventListener(
'click', function () {
resetMainTimer(15*60);
timer.start();
});
document.getElementById('btn_custom').addEventListener(
'click', function () {
customUnits = document.getElementById('custom_units').value
if (customUnits === 'minutes') {
resetMainTimer(customTimeInput.value*60);
} else if (customUnits === 'hours') {
resetMainTimer(customTimeInput.value*3600);
} else {
resetMainTimer(customTimeInput.value);
}
timer.start();
});
// Bind keyboard shortcut for starting/pausing timer
Mousetrap.bind('space', function(e) {
// Remove default behavior of buttons (page scrolling)
if (e.preventDefault()) {
e.preventDefault();
} else {
e.returnValue = false; //IE
}
// Pause or start the timer
if(timer.isRunning) {
timer.pause();
} else {
timer.start();
}
});
};