Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2e039a7
One asset container at a time.
duncanmcclean May 20, 2025
01337e5
Use new dropdown components
duncanmcclean May 20, 2025
e372def
Prevent warnings about `actionOpened`
duncanmcclean May 20, 2025
fb5f791
wip
duncanmcclean May 20, 2025
d3db98a
Move new folder events into `sharedAssetEvents` object
duncanmcclean May 20, 2025
dc6e733
Do away with unused asset container index view
duncanmcclean May 20, 2025
b2ee3eb
We won't be navigating between containers anymore.
duncanmcclean May 20, 2025
d786cb2
Don't keep track of container here. It never changes.
duncanmcclean May 20, 2025
e875cd7
Rename thumbnail size preference key
duncanmcclean May 20, 2025
6be4505
Ensure toggle group always has a value.
duncanmcclean May 20, 2025
33fa784
Ability to navigate between previous/next assets
duncanmcclean May 20, 2025
ce86581
Ensure folders can be created in Grid mode, when no existing folders …
duncanmcclean May 20, 2025
9da783d
Prevent the images themselves being dragged
duncanmcclean May 20, 2025
a24c92c
Drag & drop assets and folders in grid mode
duncanmcclean May 20, 2025
593f12e
Prevent upload overlay showing when dragging assets & folders
duncanmcclean May 22, 2025
971fd34
Remove data attributes. I never ended up using them.
duncanmcclean May 22, 2025
1a57ba4
Dry up new folder stuff.
duncanmcclean May 22, 2025
f344ddb
Use the same order between two asset browser components.
duncanmcclean May 22, 2025
b630bca
Merge remote-tracking branch 'origin/ui' into asset-browser
duncanmcclean May 23, 2025
e764448
Uncomment assets css
duncanmcclean May 23, 2025
8616dc4
Drag & drop assets and folders in table mode
duncanmcclean May 23, 2025
dd03e60
Prevent moving assets & folders without permission
duncanmcclean May 23, 2025
0489cb9
Add previous/next buttons
duncanmcclean May 28, 2025
49cbe0a
Only save when navigating between prev/next assets when there's dirty…
duncanmcclean May 28, 2025
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
2 changes: 1 addition & 1 deletion resources/css/cp.css
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,7 @@

/* Components */
@import './components/array.css';
/* @import './components/assets.css'; */
@import './components/assets.css';
@import './components/blueprints.css';
@import './components/cards.css';
@import './components/column-picker.css';
Expand Down
11 changes: 4 additions & 7 deletions resources/js/components/assets/AssetManager.vue
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@
ref="browser"
:can-create-containers="canCreateContainers"
:create-container-url="createContainerUrl"
:initial-container="container"
:container="container"
:initial-per-page="$config.get('paginationSize')"
:initial-editing-asset-id="initialEditingAssetId"
:selected-path="path"
Expand All@@ -18,7 +18,7 @@
<script>
export default {
props: {
initialContainer: Object,
container: Object,
initialPath: String,
initialEditingAssetId: String,
actions: Array,
Expand All@@ -28,7 +28,6 @@ export default {

data() {
return {
container: this.initialContainer,
path: this.initialPath,
selectedAssets: [],
};
Expand All@@ -49,7 +48,6 @@ export default {
window.history.replaceState({ container: { ...this.container }, path: this.path }, '');

window.onpopstate = (e) => {
this.container = e.state.container;
this.path = e.state.path;
};
},
Expand All@@ -60,10 +58,9 @@ export default {
},

/**
* When a user has navigated to another folder or container
* When a user has navigated to another folder.
*/
navigate(container, path) {
this.container = container;
navigate(path) {
this.path = path;
this.pushState();

Expand Down
79 changes: 79 additions & 0 deletions resources/js/components/assets/Browser/AssetBrowserMixin.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,25 @@ export default {
folders: Array,
path: String,
restrictFolderNavigation: Boolean,
creatingFolder: Boolean,
},

data() {
return {
newFolderName: null,
draggingAsset: null,
draggingFolder: null,
}
},

watch: {
draggingAsset() {
this.$emit('prevent-dragging', this.draggingAsset !== null);
},

draggingFolder() {
this.$emit('prevent-dragging', this.draggingFolder !== null);
},
},

methods: {
Expand All@@ -30,5 +49,65 @@ export default {
selectFolder(path) {
this.$emit('select-folder', path);
},

focusNewFolderInput() {
this.$refs.newFolderInput?.edit();
},

clearNewFolderName() {
this.newFolderName = null;
},

canMoveAsset(asset) {
return asset.actions.some((action) => action.handle === 'move_asset');
},

canMoveFolder(folder) {
return folder.actions.some((action) => action.handle === 'move_asset_folder');
},

handleFolderDrop(destinationFolder) {
if (this.draggingAsset) {
let asset = this.assets.find((asset) => asset.id === this.draggingAsset);
let action = asset.actions.find((action) => action.handle === 'move_asset');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingAsset],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.actionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingAsset = null);
}

if (this.draggingFolder) {
let folder = this.folders.find((folder) => folder.path === this.draggingFolder);
let action = folder.actions.find((action) => action.handle === 'move_asset_folder');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingFolder],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.folderActionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingFolder = null);
}
},
},
};
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2e039a7
One asset container at a time.
duncanmcclean May 20, 2025
01337e5
Use new dropdown components
duncanmcclean May 20, 2025
e372def
Prevent warnings about `actionOpened`
duncanmcclean May 20, 2025
fb5f791
wip
duncanmcclean May 20, 2025
d3db98a
Move new folder events into `sharedAssetEvents` object
duncanmcclean May 20, 2025
dc6e733
Do away with unused asset container index view
duncanmcclean May 20, 2025
b2ee3eb
We won't be navigating between containers anymore.
duncanmcclean May 20, 2025
d786cb2
Don't keep track of container here. It never changes.
duncanmcclean May 20, 2025
e875cd7
Rename thumbnail size preference key
duncanmcclean May 20, 2025
6be4505
Ensure toggle group always has a value.
duncanmcclean May 20, 2025
33fa784
Ability to navigate between previous/next assets
duncanmcclean May 20, 2025
ce86581
Ensure folders can be created in Grid mode, when no existing folders …
duncanmcclean May 20, 2025
9da783d
Prevent the images themselves being dragged
duncanmcclean May 20, 2025
a24c92c
Drag & drop assets and folders in grid mode
duncanmcclean May 20, 2025
593f12e
Prevent upload overlay showing when dragging assets & folders
duncanmcclean May 22, 2025
971fd34
Remove data attributes. I never ended up using them.
duncanmcclean May 22, 2025
1a57ba4
Dry up new folder stuff.
duncanmcclean May 22, 2025
f344ddb
Use the same order between two asset browser components.
duncanmcclean May 22, 2025
b630bca
Merge remote-tracking branch 'origin/ui' into asset-browser
duncanmcclean May 23, 2025
e764448
Uncomment assets css
duncanmcclean May 23, 2025
8616dc4
Drag & drop assets and folders in table mode
duncanmcclean May 23, 2025
dd03e60
Prevent moving assets & folders without permission
duncanmcclean May 23, 2025
0489cb9
Add previous/next buttons
duncanmcclean May 28, 2025
49cbe0a
Only save when navigating between prev/next assets when there's dirty…
duncanmcclean May 28, 2025
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
2 changes: 1 addition & 1 deletion resources/css/cp.css
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,7 @@

/* Components */
@import './components/array.css';
/* @import './components/assets.css'; */
@import './components/assets.css';
@import './components/blueprints.css';
@import './components/cards.css';
@import './components/column-picker.css';
Expand Down
11 changes: 4 additions & 7 deletions resources/js/components/assets/AssetManager.vue
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@
ref="browser"
:can-create-containers="canCreateContainers"
:create-container-url="createContainerUrl"
:initial-container="container"
:container="container"
:initial-per-page="$config.get('paginationSize')"
:initial-editing-asset-id="initialEditingAssetId"
:selected-path="path"
Expand All@@ -18,7 +18,7 @@
<script>
export default {
props: {
initialContainer: Object,
container: Object,
initialPath: String,
initialEditingAssetId: String,
actions: Array,
Expand All@@ -28,7 +28,6 @@ export default {

data() {
return {
container: this.initialContainer,
path: this.initialPath,
selectedAssets: [],
};
Expand All@@ -49,7 +48,6 @@ export default {
window.history.replaceState({ container: { ...this.container }, path: this.path }, '');

window.onpopstate = (e) => {
this.container = e.state.container;
this.path = e.state.path;
};
},
Expand All@@ -60,10 +58,9 @@ export default {
},

/**
* When a user has navigated to another folder or container
* When a user has navigated to another folder.
*/
navigate(container, path) {
this.container = container;
navigate(path) {
this.path = path;
this.pushState();

Expand Down
79 changes: 79 additions & 0 deletions resources/js/components/assets/Browser/AssetBrowserMixin.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,25 @@ export default {
folders: Array,
path: String,
restrictFolderNavigation: Boolean,
creatingFolder: Boolean,
},

data() {
return {
newFolderName: null,
draggingAsset: null,
draggingFolder: null,
}
},

watch: {
draggingAsset() {
this.$emit('prevent-dragging', this.draggingAsset !== null);
},

draggingFolder() {
this.$emit('prevent-dragging', this.draggingFolder !== null);
},
},

methods: {
Expand All@@ -30,5 +49,65 @@ export default {
selectFolder(path) {
this.$emit('select-folder', path);
},

focusNewFolderInput() {
this.$refs.newFolderInput?.edit();
},

clearNewFolderName() {
this.newFolderName = null;
},

canMoveAsset(asset) {
return asset.actions.some((action) => action.handle === 'move_asset');
},

canMoveFolder(folder) {
return folder.actions.some((action) => action.handle === 'move_asset_folder');
},

handleFolderDrop(destinationFolder) {
if (this.draggingAsset) {
let asset = this.assets.find((asset) => asset.id === this.draggingAsset);
let action = asset.actions.find((action) => action.handle === 'move_asset');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingAsset],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.actionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingAsset = null);
}

if (this.draggingFolder) {
let folder = this.folders.find((folder) => folder.path === this.draggingFolder);
let action = folder.actions.find((action) => action.handle === 'move_asset_folder');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingFolder],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.folderActionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingFolder = null);
}
},
},
};
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2e039a7
One asset container at a time.
duncanmcclean May 20, 2025
01337e5
Use new dropdown components
duncanmcclean May 20, 2025
e372def
Prevent warnings about `actionOpened`
duncanmcclean May 20, 2025
fb5f791
wip
duncanmcclean May 20, 2025
d3db98a
Move new folder events into `sharedAssetEvents` object
duncanmcclean May 20, 2025
dc6e733
Do away with unused asset container index view
duncanmcclean May 20, 2025
b2ee3eb
We won't be navigating between containers anymore.
duncanmcclean May 20, 2025
d786cb2
Don't keep track of container here. It never changes.
duncanmcclean May 20, 2025
e875cd7
Rename thumbnail size preference key
duncanmcclean May 20, 2025
6be4505
Ensure toggle group always has a value.
duncanmcclean May 20, 2025
33fa784
Ability to navigate between previous/next assets
duncanmcclean May 20, 2025
ce86581
Ensure folders can be created in Grid mode, when no existing folders …
duncanmcclean May 20, 2025
9da783d
Prevent the images themselves being dragged
duncanmcclean May 20, 2025
a24c92c
Drag & drop assets and folders in grid mode
duncanmcclean May 20, 2025
593f12e
Prevent upload overlay showing when dragging assets & folders
duncanmcclean May 22, 2025
971fd34
Remove data attributes. I never ended up using them.
duncanmcclean May 22, 2025
1a57ba4
Dry up new folder stuff.
duncanmcclean May 22, 2025
f344ddb
Use the same order between two asset browser components.
duncanmcclean May 22, 2025
b630bca
Merge remote-tracking branch 'origin/ui' into asset-browser
duncanmcclean May 23, 2025
e764448
Uncomment assets css
duncanmcclean May 23, 2025
8616dc4
Drag & drop assets and folders in table mode
duncanmcclean May 23, 2025
dd03e60
Prevent moving assets & folders without permission
duncanmcclean May 23, 2025
0489cb9
Add previous/next buttons
duncanmcclean May 28, 2025
49cbe0a
Only save when navigating between prev/next assets when there's dirty…
duncanmcclean May 28, 2025
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
2 changes: 1 addition & 1 deletion resources/css/cp.css
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,7 @@

/* Components */
@import './components/array.css';
/* @import './components/assets.css'; */
@import './components/assets.css';
@import './components/blueprints.css';
@import './components/cards.css';
@import './components/column-picker.css';
Expand Down
11 changes: 4 additions & 7 deletions resources/js/components/assets/AssetManager.vue
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@
ref="browser"
:can-create-containers="canCreateContainers"
:create-container-url="createContainerUrl"
:initial-container="container"
:container="container"
:initial-per-page="$config.get('paginationSize')"
:initial-editing-asset-id="initialEditingAssetId"
:selected-path="path"
Expand All@@ -18,7 +18,7 @@
<script>
export default {
props: {
initialContainer: Object,
container: Object,
initialPath: String,
initialEditingAssetId: String,
actions: Array,
Expand All@@ -28,7 +28,6 @@ export default {

data() {
return {
container: this.initialContainer,
path: this.initialPath,
selectedAssets: [],
};
Expand All@@ -49,7 +48,6 @@ export default {
window.history.replaceState({ container: { ...this.container }, path: this.path }, '');

window.onpopstate = (e) => {
this.container = e.state.container;
this.path = e.state.path;
};
},
Expand All@@ -60,10 +58,9 @@ export default {
},

/**
* When a user has navigated to another folder or container
* When a user has navigated to another folder.
*/
navigate(container, path) {
this.container = container;
navigate(path) {
this.path = path;
this.pushState();

Expand Down
79 changes: 79 additions & 0 deletions resources/js/components/assets/Browser/AssetBrowserMixin.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,25 @@ export default {
folders: Array,
path: String,
restrictFolderNavigation: Boolean,
creatingFolder: Boolean,
},

data() {
return {
newFolderName: null,
draggingAsset: null,
draggingFolder: null,
}
},

watch: {
draggingAsset() {
this.$emit('prevent-dragging', this.draggingAsset !== null);
},

draggingFolder() {
this.$emit('prevent-dragging', this.draggingFolder !== null);
},
},

methods: {
Expand All@@ -30,5 +49,65 @@ export default {
selectFolder(path) {
this.$emit('select-folder', path);
},

focusNewFolderInput() {
this.$refs.newFolderInput?.edit();
},

clearNewFolderName() {
this.newFolderName = null;
},

canMoveAsset(asset) {
return asset.actions.some((action) => action.handle === 'move_asset');
},

canMoveFolder(folder) {
return folder.actions.some((action) => action.handle === 'move_asset_folder');
},

handleFolderDrop(destinationFolder) {
if (this.draggingAsset) {
let asset = this.assets.find((asset) => asset.id === this.draggingAsset);
let action = asset.actions.find((action) => action.handle === 'move_asset');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingAsset],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.actionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingAsset = null);
}

if (this.draggingFolder) {
let folder = this.folders.find((folder) => folder.path === this.draggingFolder);
let action = folder.actions.find((action) => action.handle === 'move_asset_folder');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingFolder],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.folderActionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingFolder = null);
}
},
},
};
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2e039a7
One asset container at a time.
duncanmcclean May 20, 2025
01337e5
Use new dropdown components
duncanmcclean May 20, 2025
e372def
Prevent warnings about `actionOpened`
duncanmcclean May 20, 2025
fb5f791
wip
duncanmcclean May 20, 2025
d3db98a
Move new folder events into `sharedAssetEvents` object
duncanmcclean May 20, 2025
dc6e733
Do away with unused asset container index view
duncanmcclean May 20, 2025
b2ee3eb
We won't be navigating between containers anymore.
duncanmcclean May 20, 2025
d786cb2
Don't keep track of container here. It never changes.
duncanmcclean May 20, 2025
e875cd7
Rename thumbnail size preference key
duncanmcclean May 20, 2025
6be4505
Ensure toggle group always has a value.
duncanmcclean May 20, 2025
33fa784
Ability to navigate between previous/next assets
duncanmcclean May 20, 2025
ce86581
Ensure folders can be created in Grid mode, when no existing folders …
duncanmcclean May 20, 2025
9da783d
Prevent the images themselves being dragged
duncanmcclean May 20, 2025
a24c92c
Drag & drop assets and folders in grid mode
duncanmcclean May 20, 2025
593f12e
Prevent upload overlay showing when dragging assets & folders
duncanmcclean May 22, 2025
971fd34
Remove data attributes. I never ended up using them.
duncanmcclean May 22, 2025
1a57ba4
Dry up new folder stuff.
duncanmcclean May 22, 2025
f344ddb
Use the same order between two asset browser components.
duncanmcclean May 22, 2025
b630bca
Merge remote-tracking branch 'origin/ui' into asset-browser
duncanmcclean May 23, 2025
e764448
Uncomment assets css
duncanmcclean May 23, 2025
8616dc4
Drag & drop assets and folders in table mode
duncanmcclean May 23, 2025
dd03e60
Prevent moving assets & folders without permission
duncanmcclean May 23, 2025
0489cb9
Add previous/next buttons
duncanmcclean May 28, 2025
49cbe0a
Only save when navigating between prev/next assets when there's dirty…
duncanmcclean May 28, 2025
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
2 changes: 1 addition & 1 deletion resources/css/cp.css
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,7 @@

/* Components */
@import './components/array.css';
/* @import './components/assets.css'; */
@import './components/assets.css';
@import './components/blueprints.css';
@import './components/cards.css';
@import './components/column-picker.css';
Expand Down
11 changes: 4 additions & 7 deletions resources/js/components/assets/AssetManager.vue
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@
ref="browser"
:can-create-containers="canCreateContainers"
:create-container-url="createContainerUrl"
:initial-container="container"
:container="container"
:initial-per-page="$config.get('paginationSize')"
:initial-editing-asset-id="initialEditingAssetId"
:selected-path="path"
Expand All@@ -18,7 +18,7 @@
<script>
export default {
props: {
initialContainer: Object,
container: Object,
initialPath: String,
initialEditingAssetId: String,
actions: Array,
Expand All@@ -28,7 +28,6 @@ export default {

data() {
return {
container: this.initialContainer,
path: this.initialPath,
selectedAssets: [],
};
Expand All@@ -49,7 +48,6 @@ export default {
window.history.replaceState({ container: { ...this.container }, path: this.path }, '');

window.onpopstate = (e) => {
this.container = e.state.container;
this.path = e.state.path;
};
},
Expand All@@ -60,10 +58,9 @@ export default {
},

/**
* When a user has navigated to another folder or container
* When a user has navigated to another folder.
*/
navigate(container, path) {
this.container = container;
navigate(path) {
this.path = path;
this.pushState();

Expand Down
79 changes: 79 additions & 0 deletions resources/js/components/assets/Browser/AssetBrowserMixin.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,25 @@ export default {
folders: Array,
path: String,
restrictFolderNavigation: Boolean,
creatingFolder: Boolean,
},

data() {
return {
newFolderName: null,
draggingAsset: null,
draggingFolder: null,
}
},

watch: {
draggingAsset() {
this.$emit('prevent-dragging', this.draggingAsset !== null);
},

draggingFolder() {
this.$emit('prevent-dragging', this.draggingFolder !== null);
},
},

methods: {
Expand All@@ -30,5 +49,65 @@ export default {
selectFolder(path) {
this.$emit('select-folder', path);
},

focusNewFolderInput() {
this.$refs.newFolderInput?.edit();
},

clearNewFolderName() {
this.newFolderName = null;
},

canMoveAsset(asset) {
return asset.actions.some((action) => action.handle === 'move_asset');
},

canMoveFolder(folder) {
return folder.actions.some((action) => action.handle === 'move_asset_folder');
},

handleFolderDrop(destinationFolder) {
if (this.draggingAsset) {
let asset = this.assets.find((asset) => asset.id === this.draggingAsset);
let action = asset.actions.find((action) => action.handle === 'move_asset');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingAsset],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.actionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingAsset = null);
}

if (this.draggingFolder) {
let folder = this.folders.find((folder) => folder.path === this.draggingFolder);
let action = folder.actions.find((action) => action.handle === 'move_asset_folder');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingFolder],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.folderActionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingFolder = null);
}
},
},
};
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2e039a7
One asset container at a time.
duncanmcclean May 20, 2025
01337e5
Use new dropdown components
duncanmcclean May 20, 2025
e372def
Prevent warnings about `actionOpened`
duncanmcclean May 20, 2025
fb5f791
wip
duncanmcclean May 20, 2025
d3db98a
Move new folder events into `sharedAssetEvents` object
duncanmcclean May 20, 2025
dc6e733
Do away with unused asset container index view
duncanmcclean May 20, 2025
b2ee3eb
We won't be navigating between containers anymore.
duncanmcclean May 20, 2025
d786cb2
Don't keep track of container here. It never changes.
duncanmcclean May 20, 2025
e875cd7
Rename thumbnail size preference key
duncanmcclean May 20, 2025
6be4505
Ensure toggle group always has a value.
duncanmcclean May 20, 2025
33fa784
Ability to navigate between previous/next assets
duncanmcclean May 20, 2025
ce86581
Ensure folders can be created in Grid mode, when no existing folders …
duncanmcclean May 20, 2025
9da783d
Prevent the images themselves being dragged
duncanmcclean May 20, 2025
a24c92c
Drag & drop assets and folders in grid mode
duncanmcclean May 20, 2025
593f12e
Prevent upload overlay showing when dragging assets & folders
duncanmcclean May 22, 2025
971fd34
Remove data attributes. I never ended up using them.
duncanmcclean May 22, 2025
1a57ba4
Dry up new folder stuff.
duncanmcclean May 22, 2025
f344ddb
Use the same order between two asset browser components.
duncanmcclean May 22, 2025
b630bca
Merge remote-tracking branch 'origin/ui' into asset-browser
duncanmcclean May 23, 2025
e764448
Uncomment assets css
duncanmcclean May 23, 2025
8616dc4
Drag & drop assets and folders in table mode
duncanmcclean May 23, 2025
dd03e60
Prevent moving assets & folders without permission
duncanmcclean May 23, 2025
0489cb9
Add previous/next buttons
duncanmcclean May 28, 2025
49cbe0a
Only save when navigating between prev/next assets when there's dirty…
duncanmcclean May 28, 2025
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
2 changes: 1 addition & 1 deletion resources/css/cp.css
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,7 @@

/* Components */
@import './components/array.css';
/* @import './components/assets.css'; */
@import './components/assets.css';
@import './components/blueprints.css';
@import './components/cards.css';
@import './components/column-picker.css';
Expand Down
11 changes: 4 additions & 7 deletions resources/js/components/assets/AssetManager.vue
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@
ref="browser"
:can-create-containers="canCreateContainers"
:create-container-url="createContainerUrl"
:initial-container="container"
:container="container"
:initial-per-page="$config.get('paginationSize')"
:initial-editing-asset-id="initialEditingAssetId"
:selected-path="path"
Expand All@@ -18,7 +18,7 @@
<script>
export default {
props: {
initialContainer: Object,
container: Object,
initialPath: String,
initialEditingAssetId: String,
actions: Array,
Expand All@@ -28,7 +28,6 @@ export default {

data() {
return {
container: this.initialContainer,
path: this.initialPath,
selectedAssets: [],
};
Expand All@@ -49,7 +48,6 @@ export default {
window.history.replaceState({ container: { ...this.container }, path: this.path }, '');

window.onpopstate = (e) => {
this.container = e.state.container;
this.path = e.state.path;
};
},
Expand All@@ -60,10 +58,9 @@ export default {
},

/**
* When a user has navigated to another folder or container
* When a user has navigated to another folder.
*/
navigate(container, path) {
this.container = container;
navigate(path) {
this.path = path;
this.pushState();

Expand Down
79 changes: 79 additions & 0 deletions resources/js/components/assets/Browser/AssetBrowserMixin.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,25 @@ export default {
folders: Array,
path: String,
restrictFolderNavigation: Boolean,
creatingFolder: Boolean,
},

data() {
return {
newFolderName: null,
draggingAsset: null,
draggingFolder: null,
}
},

watch: {
draggingAsset() {
this.$emit('prevent-dragging', this.draggingAsset !== null);
},

draggingFolder() {
this.$emit('prevent-dragging', this.draggingFolder !== null);
},
},

methods: {
Expand All@@ -30,5 +49,65 @@ export default {
selectFolder(path) {
this.$emit('select-folder', path);
},

focusNewFolderInput() {
this.$refs.newFolderInput?.edit();
},

clearNewFolderName() {
this.newFolderName = null;
},

canMoveAsset(asset) {
return asset.actions.some((action) => action.handle === 'move_asset');
},

canMoveFolder(folder) {
return folder.actions.some((action) => action.handle === 'move_asset_folder');
},

handleFolderDrop(destinationFolder) {
if (this.draggingAsset) {
let asset = this.assets.find((asset) => asset.id === this.draggingAsset);
let action = asset.actions.find((action) => action.handle === 'move_asset');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingAsset],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.actionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingAsset = null);
}

if (this.draggingFolder) {
let folder = this.folders.find((folder) => folder.path === this.draggingFolder);
let action = folder.actions.find((action) => action.handle === 'move_asset_folder');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingFolder],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.folderActionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingFolder = null);
}
},
},
};
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2e039a7
One asset container at a time.
duncanmcclean May 20, 2025
01337e5
Use new dropdown components
duncanmcclean May 20, 2025
e372def
Prevent warnings about `actionOpened`
duncanmcclean May 20, 2025
fb5f791
wip
duncanmcclean May 20, 2025
d3db98a
Move new folder events into `sharedAssetEvents` object
duncanmcclean May 20, 2025
dc6e733
Do away with unused asset container index view
duncanmcclean May 20, 2025
b2ee3eb
We won't be navigating between containers anymore.
duncanmcclean May 20, 2025
d786cb2
Don't keep track of container here. It never changes.
duncanmcclean May 20, 2025
e875cd7
Rename thumbnail size preference key
duncanmcclean May 20, 2025
6be4505
Ensure toggle group always has a value.
duncanmcclean May 20, 2025
33fa784
Ability to navigate between previous/next assets
duncanmcclean May 20, 2025
ce86581
Ensure folders can be created in Grid mode, when no existing folders …
duncanmcclean May 20, 2025
9da783d
Prevent the images themselves being dragged
duncanmcclean May 20, 2025
a24c92c
Drag & drop assets and folders in grid mode
duncanmcclean May 20, 2025
593f12e
Prevent upload overlay showing when dragging assets & folders
duncanmcclean May 22, 2025
971fd34
Remove data attributes. I never ended up using them.
duncanmcclean May 22, 2025
1a57ba4
Dry up new folder stuff.
duncanmcclean May 22, 2025
f344ddb
Use the same order between two asset browser components.
duncanmcclean May 22, 2025
b630bca
Merge remote-tracking branch 'origin/ui' into asset-browser
duncanmcclean May 23, 2025
e764448
Uncomment assets css
duncanmcclean May 23, 2025
8616dc4
Drag & drop assets and folders in table mode
duncanmcclean May 23, 2025
dd03e60
Prevent moving assets & folders without permission
duncanmcclean May 23, 2025
0489cb9
Add previous/next buttons
duncanmcclean May 28, 2025
49cbe0a
Only save when navigating between prev/next assets when there's dirty…
duncanmcclean May 28, 2025
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
2 changes: 1 addition & 1 deletion resources/css/cp.css
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,7 @@

/* Components */
@import './components/array.css';
/* @import './components/assets.css'; */
@import './components/assets.css';
@import './components/blueprints.css';
@import './components/cards.css';
@import './components/column-picker.css';
Expand Down
11 changes: 4 additions & 7 deletions resources/js/components/assets/AssetManager.vue
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@
ref="browser"
:can-create-containers="canCreateContainers"
:create-container-url="createContainerUrl"
:initial-container="container"
:container="container"
:initial-per-page="$config.get('paginationSize')"
:initial-editing-asset-id="initialEditingAssetId"
:selected-path="path"
Expand All@@ -18,7 +18,7 @@
<script>
export default {
props: {
initialContainer: Object,
container: Object,
initialPath: String,
initialEditingAssetId: String,
actions: Array,
Expand All@@ -28,7 +28,6 @@ export default {

data() {
return {
container: this.initialContainer,
path: this.initialPath,
selectedAssets: [],
};
Expand All@@ -49,7 +48,6 @@ export default {
window.history.replaceState({ container: { ...this.container }, path: this.path }, '');

window.onpopstate = (e) => {
this.container = e.state.container;
this.path = e.state.path;
};
},
Expand All@@ -60,10 +58,9 @@ export default {
},

/**
* When a user has navigated to another folder or container
* When a user has navigated to another folder.
*/
navigate(container, path) {
this.container = container;
navigate(path) {
this.path = path;
this.pushState();

Expand Down
79 changes: 79 additions & 0 deletions resources/js/components/assets/Browser/AssetBrowserMixin.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,25 @@ export default {
folders: Array,
path: String,
restrictFolderNavigation: Boolean,
creatingFolder: Boolean,
},

data() {
return {
newFolderName: null,
draggingAsset: null,
draggingFolder: null,
}
},

watch: {
draggingAsset() {
this.$emit('prevent-dragging', this.draggingAsset !== null);
},

draggingFolder() {
this.$emit('prevent-dragging', this.draggingFolder !== null);
},
},

methods: {
Expand All@@ -30,5 +49,65 @@ export default {
selectFolder(path) {
this.$emit('select-folder', path);
},

focusNewFolderInput() {
this.$refs.newFolderInput?.edit();
},

clearNewFolderName() {
this.newFolderName = null;
},

canMoveAsset(asset) {
return asset.actions.some((action) => action.handle === 'move_asset');
},

canMoveFolder(folder) {
return folder.actions.some((action) => action.handle === 'move_asset_folder');
},

handleFolderDrop(destinationFolder) {
if (this.draggingAsset) {
let asset = this.assets.find((asset) => asset.id === this.draggingAsset);
let action = asset.actions.find((action) => action.handle === 'move_asset');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingAsset],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.actionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingAsset = null);
}

if (this.draggingFolder) {
let folder = this.folders.find((folder) => folder.path === this.draggingFolder);
let action = folder.actions.find((action) => action.handle === 'move_asset_folder');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingFolder],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.folderActionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingFolder = null);
}
},
},
};
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2e039a7
One asset container at a time.
duncanmcclean May 20, 2025
01337e5
Use new dropdown components
duncanmcclean May 20, 2025
e372def
Prevent warnings about `actionOpened`
duncanmcclean May 20, 2025
fb5f791
wip
duncanmcclean May 20, 2025
d3db98a
Move new folder events into `sharedAssetEvents` object
duncanmcclean May 20, 2025
dc6e733
Do away with unused asset container index view
duncanmcclean May 20, 2025
b2ee3eb
We won't be navigating between containers anymore.
duncanmcclean May 20, 2025
d786cb2
Don't keep track of container here. It never changes.
duncanmcclean May 20, 2025
e875cd7
Rename thumbnail size preference key
duncanmcclean May 20, 2025
6be4505
Ensure toggle group always has a value.
duncanmcclean May 20, 2025
33fa784
Ability to navigate between previous/next assets
duncanmcclean May 20, 2025
ce86581
Ensure folders can be created in Grid mode, when no existing folders …
duncanmcclean May 20, 2025
9da783d
Prevent the images themselves being dragged
duncanmcclean May 20, 2025
a24c92c
Drag & drop assets and folders in grid mode
duncanmcclean May 20, 2025
593f12e
Prevent upload overlay showing when dragging assets & folders
duncanmcclean May 22, 2025
971fd34
Remove data attributes. I never ended up using them.
duncanmcclean May 22, 2025
1a57ba4
Dry up new folder stuff.
duncanmcclean May 22, 2025
f344ddb
Use the same order between two asset browser components.
duncanmcclean May 22, 2025
b630bca
Merge remote-tracking branch 'origin/ui' into asset-browser
duncanmcclean May 23, 2025
e764448
Uncomment assets css
duncanmcclean May 23, 2025
8616dc4
Drag & drop assets and folders in table mode
duncanmcclean May 23, 2025
dd03e60
Prevent moving assets & folders without permission
duncanmcclean May 23, 2025
0489cb9
Add previous/next buttons
duncanmcclean May 28, 2025
49cbe0a
Only save when navigating between prev/next assets when there's dirty…
duncanmcclean May 28, 2025
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
2 changes: 1 addition & 1 deletion resources/css/cp.css
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,7 @@

/* Components */
@import './components/array.css';
/* @import './components/assets.css'; */
@import './components/assets.css';
@import './components/blueprints.css';
@import './components/cards.css';
@import './components/column-picker.css';
Expand Down
11 changes: 4 additions & 7 deletions resources/js/components/assets/AssetManager.vue
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@
ref="browser"
:can-create-containers="canCreateContainers"
:create-container-url="createContainerUrl"
:initial-container="container"
:container="container"
:initial-per-page="$config.get('paginationSize')"
:initial-editing-asset-id="initialEditingAssetId"
:selected-path="path"
Expand All@@ -18,7 +18,7 @@
<script>
export default {
props: {
initialContainer: Object,
container: Object,
initialPath: String,
initialEditingAssetId: String,
actions: Array,
Expand All@@ -28,7 +28,6 @@ export default {

data() {
return {
container: this.initialContainer,
path: this.initialPath,
selectedAssets: [],
};
Expand All@@ -49,7 +48,6 @@ export default {
window.history.replaceState({ container: { ...this.container }, path: this.path }, '');

window.onpopstate = (e) => {
this.container = e.state.container;
this.path = e.state.path;
};
},
Expand All@@ -60,10 +58,9 @@ export default {
},

/**
* When a user has navigated to another folder or container
* When a user has navigated to another folder.
*/
navigate(container, path) {
this.container = container;
navigate(path) {
this.path = path;
this.pushState();

Expand Down
79 changes: 79 additions & 0 deletions resources/js/components/assets/Browser/AssetBrowserMixin.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,25 @@ export default {
folders: Array,
path: String,
restrictFolderNavigation: Boolean,
creatingFolder: Boolean,
},

data() {
return {
newFolderName: null,
draggingAsset: null,
draggingFolder: null,
}
},

watch: {
draggingAsset() {
this.$emit('prevent-dragging', this.draggingAsset !== null);
},

draggingFolder() {
this.$emit('prevent-dragging', this.draggingFolder !== null);
},
},

methods: {
Expand All@@ -30,5 +49,65 @@ export default {
selectFolder(path) {
this.$emit('select-folder', path);
},

focusNewFolderInput() {
this.$refs.newFolderInput?.edit();
},

clearNewFolderName() {
this.newFolderName = null;
},

canMoveAsset(asset) {
return asset.actions.some((action) => action.handle === 'move_asset');
},

canMoveFolder(folder) {
return folder.actions.some((action) => action.handle === 'move_asset_folder');
},

handleFolderDrop(destinationFolder) {
if (this.draggingAsset) {
let asset = this.assets.find((asset) => asset.id === this.draggingAsset);
let action = asset.actions.find((action) => action.handle === 'move_asset');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingAsset],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.actionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingAsset = null);
}

if (this.draggingFolder) {
let folder = this.folders.find((folder) => folder.path === this.draggingFolder);
let action = folder.actions.find((action) => action.handle === 'move_asset_folder');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingFolder],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.folderActionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingFolder = null);
}
},
},
};
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2e039a7
One asset container at a time.
duncanmcclean May 20, 2025
01337e5
Use new dropdown components
duncanmcclean May 20, 2025
e372def
Prevent warnings about `actionOpened`
duncanmcclean May 20, 2025
fb5f791
wip
duncanmcclean May 20, 2025
d3db98a
Move new folder events into `sharedAssetEvents` object
duncanmcclean May 20, 2025
dc6e733
Do away with unused asset container index view
duncanmcclean May 20, 2025
b2ee3eb
We won't be navigating between containers anymore.
duncanmcclean May 20, 2025
d786cb2
Don't keep track of container here. It never changes.
duncanmcclean May 20, 2025
e875cd7
Rename thumbnail size preference key
duncanmcclean May 20, 2025
6be4505
Ensure toggle group always has a value.
duncanmcclean May 20, 2025
33fa784
Ability to navigate between previous/next assets
duncanmcclean May 20, 2025
ce86581
Ensure folders can be created in Grid mode, when no existing folders …
duncanmcclean May 20, 2025
9da783d
Prevent the images themselves being dragged
duncanmcclean May 20, 2025
a24c92c
Drag & drop assets and folders in grid mode
duncanmcclean May 20, 2025
593f12e
Prevent upload overlay showing when dragging assets & folders
duncanmcclean May 22, 2025
971fd34
Remove data attributes. I never ended up using them.
duncanmcclean May 22, 2025
1a57ba4
Dry up new folder stuff.
duncanmcclean May 22, 2025
f344ddb
Use the same order between two asset browser components.
duncanmcclean May 22, 2025
b630bca
Merge remote-tracking branch 'origin/ui' into asset-browser
duncanmcclean May 23, 2025
e764448
Uncomment assets css
duncanmcclean May 23, 2025
8616dc4
Drag & drop assets and folders in table mode
duncanmcclean May 23, 2025
dd03e60
Prevent moving assets & folders without permission
duncanmcclean May 23, 2025
0489cb9
Add previous/next buttons
duncanmcclean May 28, 2025
49cbe0a
Only save when navigating between prev/next assets when there's dirty…
duncanmcclean May 28, 2025
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
2 changes: 1 addition & 1 deletion resources/css/cp.css
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,7 @@

/* Components */
@import './components/array.css';
/* @import './components/assets.css'; */
@import './components/assets.css';
@import './components/blueprints.css';
@import './components/cards.css';
@import './components/column-picker.css';
Expand Down
11 changes: 4 additions & 7 deletions resources/js/components/assets/AssetManager.vue
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@
ref="browser"
:can-create-containers="canCreateContainers"
:create-container-url="createContainerUrl"
:initial-container="container"
:container="container"
:initial-per-page="$config.get('paginationSize')"
:initial-editing-asset-id="initialEditingAssetId"
:selected-path="path"
Expand All@@ -18,7 +18,7 @@
<script>
export default {
props: {
initialContainer: Object,
container: Object,
initialPath: String,
initialEditingAssetId: String,
actions: Array,
Expand All@@ -28,7 +28,6 @@ export default {

data() {
return {
container: this.initialContainer,
path: this.initialPath,
selectedAssets: [],
};
Expand All@@ -49,7 +48,6 @@ export default {
window.history.replaceState({ container: { ...this.container }, path: this.path }, '');

window.onpopstate = (e) => {
this.container = e.state.container;
this.path = e.state.path;
};
},
Expand All@@ -60,10 +58,9 @@ export default {
},

/**
* When a user has navigated to another folder or container
* When a user has navigated to another folder.
*/
navigate(container, path) {
this.container = container;
navigate(path) {
this.path = path;
this.pushState();

Expand Down
79 changes: 79 additions & 0 deletions resources/js/components/assets/Browser/AssetBrowserMixin.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,25 @@ export default {
folders: Array,
path: String,
restrictFolderNavigation: Boolean,
creatingFolder: Boolean,
},

data() {
return {
newFolderName: null,
draggingAsset: null,
draggingFolder: null,
}
},

watch: {
draggingAsset() {
this.$emit('prevent-dragging', this.draggingAsset !== null);
},

draggingFolder() {
this.$emit('prevent-dragging', this.draggingFolder !== null);
},
},

methods: {
Expand All@@ -30,5 +49,65 @@ export default {
selectFolder(path) {
this.$emit('select-folder', path);
},

focusNewFolderInput() {
this.$refs.newFolderInput?.edit();
},

clearNewFolderName() {
this.newFolderName = null;
},

canMoveAsset(asset) {
return asset.actions.some((action) => action.handle === 'move_asset');
},

canMoveFolder(folder) {
return folder.actions.some((action) => action.handle === 'move_asset_folder');
},

handleFolderDrop(destinationFolder) {
if (this.draggingAsset) {
let asset = this.assets.find((asset) => asset.id === this.draggingAsset);
let action = asset.actions.find((action) => action.handle === 'move_asset');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingAsset],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.actionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingAsset = null);
}

if (this.draggingFolder) {
let folder = this.folders.find((folder) => folder.path === this.draggingFolder);
let action = folder.actions.find((action) => action.handle === 'move_asset_folder');

if (!action) {
return;
}

const payload = {
action: action.handle,
context: action.context,
selections: [this.draggingFolder],
values: { folder: destinationFolder.path },
};

this.$axios
.post(this.folderActionUrl, payload)
.then(response => this.$emit('action-completed', true, response))
.finally(() => this.draggingFolder = null);
}
},
},
};
Loading
Loading